sol-parser-sdk 0.5.18 → 0.5.20

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.
package/README.md CHANGED
@@ -24,15 +24,27 @@ Parser SDK language versions and related Rust SDKs:
24
24
 
25
25
  | Language | Repository | Description | Version |
26
26
  |----------|------------|-------------|---------|
27
- | Rust | [sol-parser-sdk](https://github.com/0xfnzero/sol-parser-sdk) | Solana DEX transaction and account event parsing |
28
- | Node.js | [sol-parser-sdk-nodejs](https://github.com/0xfnzero/sol-parser-sdk-nodejs) | TypeScript/JavaScript for Node.js |
29
- | Python | [sol-parser-sdk-python](https://github.com/0xfnzero/sol-parser-sdk-python) | Async/await native support |
30
- | Go | [sol-parser-sdk-golang](https://github.com/0xfnzero/sol-parser-sdk-golang) | Go transaction and account event parsing |
31
- | **Rust** | [sol-shred-sdk](https://github.com/0xfnzero/sol-shred-sdk) | Raw Solana shred decoding and ShredStream DEX event parsing | `v4.0.3` |
32
- | **Rust** | [sol-trade-sdk](https://github.com/0xfnzero/sol-trade-sdk) | Solana DEX trade construction and transaction execution | `v6.0.0` |
27
+ | Rust | [sol-parser-sdk](https://github.com/0xfnzero/sol-parser-sdk) | Solana DEX transaction and account event parsing | `v0.7.14` |
28
+ | Node.js | [sol-parser-sdk-nodejs](https://github.com/0xfnzero/sol-parser-sdk-nodejs) | TypeScript/JavaScript for Node.js | `v0.5.20` |
29
+ | Python | [sol-parser-sdk-python](https://github.com/0xfnzero/sol-parser-sdk-python) | Async/await native support | `v0.5.13` |
30
+ | Go | [sol-parser-sdk-golang](https://github.com/0xfnzero/sol-parser-sdk-golang) | Go transaction and account event parsing | `v0.5.13` |
31
+ | **Rust** | [sol-shred-sdk](https://github.com/0xfnzero/sol-shred-sdk) | Raw Solana shred decoding and ShredStream DEX event parsing | `v4.0.5` |
32
+ | **Rust** | [sol-trade-sdk](https://github.com/0xfnzero/sol-trade-sdk) | Solana DEX trade construction and transaction execution | `v6.0.2` |
33
33
 
34
34
  ---
35
35
 
36
+ ## v0.5.20 — Pump routes and offline replay
37
+
38
+ Adds native Pump route-intent parsing for official multi-hop instructions and the exact RapidBuy/BuyPumpDelta wrapper layouts captured in reported transactions. Adds locally cached ALT resolution and rejects unresolved account identities by default, with explicit best-effort compatibility APIs where supported. Route intents expose instruction constraints and hop identities; confirmed execution amounts require execution metadata.
39
+
40
+ Includes the latest complete implementation, signed transaction fixtures, native offline-bank regression examples and reproducible local hot-path benchmarks. Unknown wrapper layouts are not inferred from embedded bytes. Local tests do not measure production network latency.
41
+
42
+ ## v0.5.19 — Pump depth-2 compatibility
43
+
44
+ Adds signed Pump depth-2 create-event replay coverage, including ALT-loaded accounts and executed logs. Existing event layouts and public parsing interfaces remain unchanged.
45
+
46
+ Validation includes official Pump SDK 4.1.0 instruction comparisons, signed local LiteSVM simulations and SDK regressions. Local simulation state/config is synthetic; no funded transactions were broadcast and production latency was not measured.
47
+
36
48
  ## v0.5.18 — Signed transaction and hot-path hardening
37
49
 
38
50
  Hardens signed transaction sanitization, loaded-address boundaries, ordered stream filtering and parser lifecycle. Aligns CLMM and DEX instruction/event layouts, nested CPI route attribution and liquidity/reward accounting. Adds independently signed wire fixtures, ALT failure cases and offline bank regressions.
@@ -113,7 +125,7 @@ Validation includes local CPU benchmarks and offline signed-bank scenarios. Meas
113
125
  **From npm**
114
126
 
115
127
  ```bash
116
- npm install sol-parser-sdk@0.5.18
128
+ npm install sol-parser-sdk@0.5.20
117
129
  ```
118
130
 
119
131
  **From source** (folder may be named `sol-parser-sdk-ts` in a monorepo)
@@ -280,7 +292,7 @@ The client decodes gRPC `entries` bytes in **TypeScript** (same layout as the Go
280
292
  npx tsx examples/shredstream_example.ts -- --url=http://127.0.0.1:10800
281
293
  ```
282
294
 
283
- Without `connection` or prewarmed ALT snapshots, V0 ALT-loaded indexes retain the static-account, default-pubkey best-effort behavior. With `connection` or `address_lookup_tables`, parsing uses complete cached ALT snapshots only: a cache miss skips the entire transaction, increments `getReceiveStats().altCacheMissTransactions`, and is never replayed. `connection` performs RPC only during explicit `await client.preloadAddressLookupTables(altAddresses)` before subscribing and in the independent background refresher (default 1000 ms, at most one request in flight). Supply already loaded tables via `config.address_lookup_tables` to avoid cold misses. The cache and pending refresh queue each retain at most 2048 tables; refreshed snapshots apply only to later messages. `shredstream_pumpfun_json.ts` uses **`RPC_URL`** (or `--rpc`) for this background refresh; its entry parsing never waits for RPC.
295
+ Without `connection` or prewarmed ALT snapshots, instructions containing unresolved indexes are skipped. Legacy placeholder behavior is available only through the explicit `dexEventsFromShredWasmTxBestEffort` API. With `connection` or `address_lookup_tables`, parsing uses complete cached ALT snapshots only: a cache miss skips the entire transaction, increments `getReceiveStats().altCacheMissTransactions`, and is never replayed. `connection` performs RPC only during explicit `await client.preloadAddressLookupTables(altAddresses)` before subscribing and in the independent background refresher (default 1000 ms, at most one request in flight). Supply already loaded tables via `config.address_lookup_tables` to avoid cold misses. The cache and pending refresh queue each retain at most 2048 tables; refreshed snapshots apply only to later messages. `shredstream_pumpfun_json.ts` uses **`RPC_URL`** (or `--rpc`) for this background refresh; its entry parsing never waits for RPC.
284
296
 
285
297
  ---
286
298
 
@@ -291,29 +303,29 @@ From the **package root** after `npm install`. Examples use `npx tsx` and load `
291
303
  | Description | Run command | Source |
292
304
  |-------------|-------------|--------|
293
305
  | **Scripts** | | |
294
- | gRPC integration test (PumpFun + PumpSwap, account-filled `DexEvent`) | `npx tsx scripts/test-grpc-ts.ts` | [test-grpc-ts.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/scripts/test-grpc-ts.ts) |
295
- | Debug: print `metaRaw` / log structure | `npx tsx scripts/debug-grpc-ts.ts` | [debug-grpc-ts.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/scripts/debug-grpc-ts.ts) |
306
+ | gRPC integration test (PumpFun + PumpSwap, account-filled `DexEvent`) | `npx tsx scripts/test-grpc-ts.ts` | [test-grpc-ts.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/scripts/test-grpc-ts.ts) | `v0.5.20` |
307
+ | Debug: print `metaRaw` / log structure | `npx tsx scripts/debug-grpc-ts.ts` | [debug-grpc-ts.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/scripts/debug-grpc-ts.ts) | `v0.5.20` |
296
308
  | **PumpFun** | | |
297
- | CREATE + dev BUY/SELL, long-running low latency | `npx tsx examples/devtrades_low_latency.ts` | [devtrades_low_latency.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/devtrades_low_latency.ts) |
298
- | PumpFun + full-volume PumpSwap dev trades/liquidity | `npm run example:grpc:devtrades:pumpswap` | [devtrades_pumpfun_pumpswap_low_latency.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/devtrades_pumpfun_pumpswap_low_latency.ts) |
299
- | Pretty-print full JSON `DexEvent` over gRPC | `npx tsx examples/pumpfun_grpc_json.ts` | [pumpfun_grpc_json.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/pumpfun_grpc_json.ts) |
300
- | PumpFun events + metrics | `npx tsx examples/pumpfun_with_metrics.ts` | [pumpfun_with_metrics.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/pumpfun_with_metrics.ts) |
301
- | PumpFun trade filter | `npx tsx examples/pumpfun_trade_filter.ts` | [pumpfun_trade_filter.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/pumpfun_trade_filter.ts) |
302
- | Quick PumpFun connection test | `npx tsx examples/pumpfun_quick_test.ts` | [pumpfun_quick_test.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/pumpfun_quick_test.ts) |
309
+ | CREATE + dev BUY/SELL, long-running low latency | `npx tsx examples/devtrades_low_latency.ts` | [devtrades_low_latency.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/devtrades_low_latency.ts) | `v0.5.20` |
310
+ | PumpFun + full-volume PumpSwap dev trades/liquidity | `npm run example:grpc:devtrades:pumpswap` | [devtrades_pumpfun_pumpswap_low_latency.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/devtrades_pumpfun_pumpswap_low_latency.ts) | `v0.5.20` |
311
+ | Pretty-print full JSON `DexEvent` over gRPC | `npx tsx examples/pumpfun_grpc_json.ts` | [pumpfun_grpc_json.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/pumpfun_grpc_json.ts) | `v0.5.20` |
312
+ | PumpFun events + metrics | `npx tsx examples/pumpfun_with_metrics.ts` | [pumpfun_with_metrics.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/pumpfun_with_metrics.ts) | `v0.5.20` |
313
+ | PumpFun trade filter | `npx tsx examples/pumpfun_trade_filter.ts` | [pumpfun_trade_filter.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/pumpfun_trade_filter.ts) | `v0.5.20` |
314
+ | Quick PumpFun connection test | `npx tsx examples/pumpfun_quick_test.ts` | [pumpfun_quick_test.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/pumpfun_quick_test.ts) | `v0.5.20` |
303
315
  | **PumpSwap** | | |
304
- | Pretty-print full JSON `DexEvent` over gRPC | `npx tsx examples/pumpswap_grpc_json.ts` | [pumpswap_grpc_json.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/pumpswap_grpc_json.ts) |
305
- | PumpSwap events + metrics | `npx tsx examples/pumpswap_with_metrics.ts` | [pumpswap_with_metrics.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/pumpswap_with_metrics.ts) |
306
- | PumpSwap swaps, pool creation, and liquidity events (ultra-low latency) | `npm run example:grpc:pumpswap` | [pumpswap_low_latency.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/pumpswap_low_latency.ts) |
316
+ | Pretty-print full JSON `DexEvent` over gRPC | `npx tsx examples/pumpswap_grpc_json.ts` | [pumpswap_grpc_json.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/pumpswap_grpc_json.ts) | `v0.5.20` |
317
+ | PumpSwap events + metrics | `npx tsx examples/pumpswap_with_metrics.ts` | [pumpswap_with_metrics.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/pumpswap_with_metrics.ts) | `v0.5.20` |
318
+ | PumpSwap swaps, pool creation, and liquidity events (ultra-low latency) | `npm run example:grpc:pumpswap` | [pumpswap_low_latency.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/pumpswap_low_latency.ts) | `v0.5.20` |
307
319
  | **Meteora DAMM** | | |
308
- | Meteora DAMM V2 events | `npx tsx examples/meteora_damm_grpc.ts` | [meteora_damm_grpc.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/meteora_damm_grpc.ts) |
320
+ | Meteora DAMM V2 events | `npx tsx examples/meteora_damm_grpc.ts` | [meteora_damm_grpc.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/meteora_damm_grpc.ts) | `v0.5.20` |
309
321
  | **ShredStream** (HTTP, not Yellowstone gRPC; see **step 5** above) | | |
310
- | Ultra-low-latency subscribe + queue / latency stats. URL: `--url` / `SHREDSTREAM_URL` / `.env` (default `http://127.0.0.1:10800`). | `npx tsx examples/shredstream_example.ts` | [shredstream_example.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/shredstream_example.ts) |
311
- | PumpFun `DexEvent` JSON from ShredStream; RPC (`RPC_URL` or `--rpc`) refreshes ALT snapshots outside parsing. Cold cache misses are skipped, counted, and not replayed; prewarm required tables. | `npx tsx examples/shredstream_pumpfun_json.ts` | [shredstream_pumpfun_json.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/shredstream_pumpfun_json.ts) |
322
+ | Ultra-low-latency subscribe + queue / latency stats. URL: `--url` / `SHREDSTREAM_URL` / `.env` (default `http://127.0.0.1:10800`). | `npx tsx examples/shredstream_example.ts` | [shredstream_example.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/shredstream_example.ts) | `v0.5.20` |
323
+ | PumpFun `DexEvent` JSON from ShredStream; RPC (`RPC_URL` or `--rpc`) refreshes ALT snapshots outside parsing. Cold cache misses are skipped, counted, and not replayed; prewarm required tables. | `npx tsx examples/shredstream_pumpfun_json.ts` | [shredstream_pumpfun_json.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/shredstream_pumpfun_json.ts) | `v0.5.20` |
312
324
  | **Multi-protocol** | | |
313
- | Subscribe to all DEX protocols | `npx tsx examples/multi_protocol_grpc.ts` | [multi_protocol_grpc.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/multi_protocol_grpc.ts) |
325
+ | Subscribe to all DEX protocols | `npx tsx examples/multi_protocol_grpc.ts` | [multi_protocol_grpc.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/multi_protocol_grpc.ts) | `v0.5.20` |
314
326
  | **Utility** | | |
315
- | Verify `onUpdate` sync errors do not kill the gRPC stream | `npx tsx examples/grpc_onupdate_error_test.ts` | [grpc_onupdate_error_test.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/grpc_onupdate_error_test.ts) |
316
- | Parse tx by signature (`parseTransactionFromRpc`; not gRPC). Set `TX_SIGNATURE` in `.env` or env. | `npx tsx examples/parse_tx_by_signature.ts` | [parse_tx_by_signature.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/parse_tx_by_signature.ts) |
327
+ | Verify `onUpdate` sync errors do not kill the gRPC stream | `npx tsx examples/grpc_onupdate_error_test.ts` | [grpc_onupdate_error_test.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/grpc_onupdate_error_test.ts) | `v0.5.20` |
328
+ | Parse tx by signature (`parseTransactionFromRpc`; not gRPC). Set `TX_SIGNATURE` in `.env` or env. | `npx tsx examples/parse_tx_by_signature.ts` | [parse_tx_by_signature.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/parse_tx_by_signature.ts) | `v0.5.20` |
317
329
 
318
330
  **`npm run` aliases** (same source files as the ShredStream rows above):
319
331
 
@@ -360,3 +372,24 @@ Full cross-language API parity is still in progress. See the [API migration guid
360
372
  实时 parser → trade 接入使用 Yellowstone **gRPC**;见 [gRPC 缓存接入与三语言示例](docs/USAGE.md#grpc-cache)。此路径不使用 WebSocket,报价和构建热路径不调用 RPC。
361
373
 
362
374
  Shared PumpFun create/create_v2 mainnet fixtures, replay instructions and verification limits are documented in the [validation guide](https://github.com/0xfnzero/sol-parser-sdk-golang/tree/main/validation/pumpfun_create_20261007).
375
+
376
+ ### Offline Pump ShredStream regressions
377
+
378
+ Pump route intents, strict cached ALT resolution and native signed replay/SBF simulation examples are documented in [examples/offline_bank/README.md](examples/offline_bank/README.md). Run the language-native examples and tests from this repository; no other-language test driver or RPC endpoint is needed. Unresolved instructions now skip by default; use the explicit best-effort API only for legacy behavior. Route intents must not be treated as confirmed fills.
379
+
380
+ ### Repeatable local hot-path benchmark
381
+
382
+ ```sh
383
+ npx tsx examples/hotpath_benchmark.ts
384
+ # Optional: pass the path to your edited JSON configuration
385
+ npx tsx examples/hotpath_benchmark.ts examples/hotpath_benchmark.json
386
+ ```
387
+
388
+ The checked-in JSON config controls warmup, sample count and batch size. Fixture
389
+ loading and setup occur before timing; timed loops perform no RPC or network I/O.
390
+ The fixed workloads use captured signed wrapped-program transactions, including
391
+ ALTs, and measure resolved parsing and wire decoding plus parsing separately.
392
+ Output reports p50/p95/p99 of batch-normalized microseconds per transaction, a
393
+ checksum and runtime metadata. These local CPU distributions include scheduling
394
+ and GC effects; they measure neither provider/network latency nor production
395
+ landing speed. Compare warmed runs with the same runtime, config and host load.
package/README_CN.md CHANGED
@@ -24,12 +24,12 @@
24
24
 
25
25
  | 语言 | 仓库 | 描述 | 版本 |
26
26
  |------|------|------|
27
- | Rust | [sol-parser-sdk](https://github.com/0xfnzero/sol-parser-sdk) | Solana DEX 交易与账户事件解析 |
28
- | Node.js | [sol-parser-sdk-nodejs](https://github.com/0xfnzero/sol-parser-sdk-nodejs) | TypeScript/JavaScript,Node.js 支持 |
29
- | Python | [sol-parser-sdk-python](https://github.com/0xfnzero/sol-parser-sdk-python) | 原生 async/await 支持 |
30
- | Go | [sol-parser-sdk-golang](https://github.com/0xfnzero/sol-parser-sdk-golang) | Go 交易与账户事件解析 |
31
- | **Rust** | [sol-shred-sdk](https://github.com/0xfnzero/sol-shred-sdk) | Solana 原始 shred 解码与 ShredStream DEX 事件解析 | `v4.0.3` |
32
- | **Rust** | [sol-trade-sdk](https://github.com/0xfnzero/sol-trade-sdk) | Solana DEX 交易构建与交易执行 | `v6.0.0` |
27
+ | Rust | [sol-parser-sdk](https://github.com/0xfnzero/sol-parser-sdk) | Solana DEX 交易与账户事件解析 | `v0.7.14` |
28
+ | Node.js | [sol-parser-sdk-nodejs](https://github.com/0xfnzero/sol-parser-sdk-nodejs) | TypeScript/JavaScript,Node.js 支持 | `v0.5.20` |
29
+ | Python | [sol-parser-sdk-python](https://github.com/0xfnzero/sol-parser-sdk-python) | 原生 async/await 支持 | `v0.5.13` |
30
+ | Go | [sol-parser-sdk-golang](https://github.com/0xfnzero/sol-parser-sdk-golang) | Go 交易与账户事件解析 | `v0.5.13` |
31
+ | **Rust** | [sol-shred-sdk](https://github.com/0xfnzero/sol-shred-sdk) | Solana 原始 shred 解码与 ShredStream DEX 事件解析 | `v4.0.5` |
32
+ | **Rust** | [sol-trade-sdk](https://github.com/0xfnzero/sol-trade-sdk) | Solana DEX 交易构建与交易执行 | `v6.0.2` |
33
33
 
34
34
  ---
35
35
 
@@ -48,6 +48,18 @@
48
48
 
49
49
  ## 发布说明
50
50
 
51
+ ## v0.5.20 — Pump routes and offline replay
52
+
53
+ Adds native Pump route-intent parsing for official multi-hop instructions and the exact RapidBuy/BuyPumpDelta wrapper layouts captured in reported transactions. Adds locally cached ALT resolution and rejects unresolved account identities by default, with explicit best-effort compatibility APIs where supported. Route intents expose instruction constraints and hop identities; confirmed execution amounts require execution metadata.
54
+
55
+ Includes the latest complete implementation, signed transaction fixtures, native offline-bank regression examples and reproducible local hot-path benchmarks. Unknown wrapper layouts are not inferred from embedded bytes. Local tests do not measure production network latency.
56
+
57
+ ## v0.5.19 — Pump depth-2 compatibility
58
+
59
+ Adds signed Pump depth-2 create-event replay coverage, including ALT-loaded accounts and executed logs. Existing event layouts and public parsing interfaces remain unchanged.
60
+
61
+ Validation includes official Pump SDK 4.1.0 instruction comparisons, signed local LiteSVM simulations and SDK regressions. Local simulation state/config is synthetic; no funded transactions were broadcast and production latency was not measured.
62
+
51
63
  ## v0.5.18 — Signed transaction and hot-path hardening
52
64
 
53
65
  Hardens signed transaction sanitization, loaded-address boundaries, ordered stream filtering and parser lifecycle. Aligns CLMM and DEX instruction/event layouts, nested CPI route attribution and liquidity/reward accounting. Adds independently signed wire fixtures, ALT failure cases and offline bank regressions.
@@ -113,7 +125,7 @@ Validation includes local CPU benchmarks and offline signed-bank scenarios. Meas
113
125
  **npm**
114
126
 
115
127
  ```bash
116
- npm install sol-parser-sdk@0.5.18
128
+ npm install sol-parser-sdk@0.5.20
117
129
  ```
118
130
 
119
131
  **源码**(monorepo 里目录可能是 `sol-parser-sdk-ts`)
@@ -273,7 +285,7 @@ mint 或 quote mint 映射到 pool,再将 `PumpSwapLiquidityAdded.user` 与该
273
285
  npx tsx examples/shredstream_example.ts -- --url=http://127.0.0.1:10800
274
286
  ```
275
287
 
276
- 未配置 `connection` 或预热 ALT 快照时,保留静态账户表及默认 pubkey 占位的 best-effort 行为。配置 `connection` 或 `address_lookup_tables` 后,解析只读取完整的 ALT 缓存快照:缓存 miss 跳过整笔交易,累计 `getReceiveStats().altCacheMissTransactions`,不会重放。`connection` 仅用于订阅前显式调用 `await client.preloadAddressLookupTables(altAddresses)` 预热,以及独立后台刷新任务(默认间隔 1000 毫秒,最多一个请求在途);也可通过 `config.address_lookup_tables` 注入已加载的快照。缓存和待刷新队列各最多保留 2048 张表,刷新结果只供后续消息使用。`shredstream_pumpfun_json.ts` 的 **`RPC_URL`**(或 `--rpc`)用于后台刷新,Entry 解析不等待 RPC。
288
+ 未配置 `connection` 或预热 ALT 快照时,默认跳过含未解析索引的指令;旧占位行为仅通过显式 `dexEventsFromShredWasmTxBestEffort` API 提供。配置 `connection` 或 `address_lookup_tables` 后,解析只读取完整的 ALT 缓存快照:缓存 miss 跳过整笔交易,累计 `getReceiveStats().altCacheMissTransactions`,不会重放。`connection` 仅用于订阅前显式调用 `await client.preloadAddressLookupTables(altAddresses)` 预热,以及独立后台刷新任务(默认间隔 1000 毫秒,最多一个请求在途);也可通过 `config.address_lookup_tables` 注入已加载的快照。缓存和待刷新队列各最多保留 2048 张表,刷新结果只供后续消息使用。`shredstream_pumpfun_json.ts` 的 **`RPC_URL`**(或 `--rpc`)用于后台刷新,Entry 解析不等待 RPC。
277
289
 
278
290
  ---
279
291
 
@@ -284,29 +296,29 @@ npx tsx examples/shredstream_example.ts -- --url=http://127.0.0.1:10800
284
296
  | 描述 | 运行命令 | 源码 |
285
297
  |------|----------|------|
286
298
  | **本包脚本** | | |
287
- | gRPC 集成测试(PumpFun + PumpSwap,账户填充后的 `DexEvent`) | `npx tsx scripts/test-grpc-ts.ts` | [test-grpc-ts.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/scripts/test-grpc-ts.ts) |
288
- | 调试:打印 `metaRaw` / 日志结构 | `npx tsx scripts/debug-grpc-ts.ts` | [debug-grpc-ts.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/scripts/debug-grpc-ts.ts) |
299
+ | gRPC 集成测试(PumpFun + PumpSwap,账户填充后的 `DexEvent`) | `npx tsx scripts/test-grpc-ts.ts` | [test-grpc-ts.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/scripts/test-grpc-ts.ts) | `v0.5.20` |
300
+ | 调试:打印 `metaRaw` / 日志结构 | `npx tsx scripts/debug-grpc-ts.ts` | [debug-grpc-ts.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/scripts/debug-grpc-ts.ts) | `v0.5.20` |
289
301
  | **PumpFun** | | |
290
- | CREATE + dev BUY/SELL 长时间低延迟订阅 | `npx tsx examples/devtrades_low_latency.ts` | [devtrades_low_latency.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/devtrades_low_latency.ts) |
291
- | PumpFun + 全量 PumpSwap 开发者交易/加池 | `npm run example:grpc:devtrades:pumpswap` | [devtrades_pumpfun_pumpswap_low_latency.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/devtrades_pumpfun_pumpswap_low_latency.ts) |
292
- | gRPC 输出完整 JSON `DexEvent` | `npx tsx examples/pumpfun_grpc_json.ts` | [pumpfun_grpc_json.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/pumpfun_grpc_json.ts) |
293
- | PumpFun 事件 + 性能指标 | `npx tsx examples/pumpfun_with_metrics.ts` | [pumpfun_with_metrics.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/pumpfun_with_metrics.ts) |
294
- | PumpFun 交易类型过滤 | `npx tsx examples/pumpfun_trade_filter.ts` | [pumpfun_trade_filter.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/pumpfun_trade_filter.ts) |
295
- | PumpFun 快速连接测试 | `npx tsx examples/pumpfun_quick_test.ts` | [pumpfun_quick_test.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/pumpfun_quick_test.ts) |
302
+ | CREATE + dev BUY/SELL 长时间低延迟订阅 | `npx tsx examples/devtrades_low_latency.ts` | [devtrades_low_latency.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/devtrades_low_latency.ts) | `v0.5.20` |
303
+ | PumpFun + 全量 PumpSwap 开发者交易/加池 | `npm run example:grpc:devtrades:pumpswap` | [devtrades_pumpfun_pumpswap_low_latency.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/devtrades_pumpfun_pumpswap_low_latency.ts) | `v0.5.20` |
304
+ | gRPC 输出完整 JSON `DexEvent` | `npx tsx examples/pumpfun_grpc_json.ts` | [pumpfun_grpc_json.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/pumpfun_grpc_json.ts) | `v0.5.20` |
305
+ | PumpFun 事件 + 性能指标 | `npx tsx examples/pumpfun_with_metrics.ts` | [pumpfun_with_metrics.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/pumpfun_with_metrics.ts) | `v0.5.20` |
306
+ | PumpFun 交易类型过滤 | `npx tsx examples/pumpfun_trade_filter.ts` | [pumpfun_trade_filter.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/pumpfun_trade_filter.ts) | `v0.5.20` |
307
+ | PumpFun 快速连接测试 | `npx tsx examples/pumpfun_quick_test.ts` | [pumpfun_quick_test.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/pumpfun_quick_test.ts) | `v0.5.20` |
296
308
  | **PumpSwap** | | |
297
- | gRPC 输出完整 JSON `DexEvent` | `npx tsx examples/pumpswap_grpc_json.ts` | [pumpswap_grpc_json.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/pumpswap_grpc_json.ts) |
298
- | PumpSwap 事件 + 性能指标 | `npx tsx examples/pumpswap_with_metrics.ts` | [pumpswap_with_metrics.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/pumpswap_with_metrics.ts) |
299
- | PumpSwap 交易、创建池及流动性事件(超低延迟) | `npm run example:grpc:pumpswap` | [pumpswap_low_latency.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/pumpswap_low_latency.ts) |
309
+ | gRPC 输出完整 JSON `DexEvent` | `npx tsx examples/pumpswap_grpc_json.ts` | [pumpswap_grpc_json.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/pumpswap_grpc_json.ts) | `v0.5.20` |
310
+ | PumpSwap 事件 + 性能指标 | `npx tsx examples/pumpswap_with_metrics.ts` | [pumpswap_with_metrics.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/pumpswap_with_metrics.ts) | `v0.5.20` |
311
+ | PumpSwap 交易、创建池及流动性事件(超低延迟) | `npm run example:grpc:pumpswap` | [pumpswap_low_latency.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/pumpswap_low_latency.ts) | `v0.5.20` |
300
312
  | **Meteora DAMM** | | |
301
- | Meteora DAMM V2 事件 | `npx tsx examples/meteora_damm_grpc.ts` | [meteora_damm_grpc.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/meteora_damm_grpc.ts) |
313
+ | Meteora DAMM V2 事件 | `npx tsx examples/meteora_damm_grpc.ts` | [meteora_damm_grpc.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/meteora_damm_grpc.ts) | `v0.5.20` |
302
314
  | **ShredStream**(HTTP,**非** Yellowstone gRPC;端点见上文步骤 5) | | |
303
- | 超低延迟订阅、队列与延迟统计。端点:`--url` / `SHREDSTREAM_URL` / `.env`(默认 `http://127.0.0.1:10800`)。 | `npx tsx examples/shredstream_example.ts` | [shredstream_example.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/shredstream_example.ts) |
304
- | ShredStream → PumpFun `DexEvent` JSON;RPC(`RPC_URL` 或 `--rpc`)只后台刷新 ALT,冷缓存 miss 跳过并计数、不重放;应预热所需表。 | `npx tsx examples/shredstream_pumpfun_json.ts` | [shredstream_pumpfun_json.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/shredstream_pumpfun_json.ts) |
315
+ | 超低延迟订阅、队列与延迟统计。端点:`--url` / `SHREDSTREAM_URL` / `.env`(默认 `http://127.0.0.1:10800`)。 | `npx tsx examples/shredstream_example.ts` | [shredstream_example.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/shredstream_example.ts) | `v0.5.20` |
316
+ | ShredStream → PumpFun `DexEvent` JSON;RPC(`RPC_URL` 或 `--rpc`)只后台刷新 ALT,冷缓存 miss 跳过并计数、不重放;应预热所需表。 | `npx tsx examples/shredstream_pumpfun_json.ts` | [shredstream_pumpfun_json.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/shredstream_pumpfun_json.ts) | `v0.5.20` |
305
317
  | **多协议** | | |
306
- | 同时订阅所有 DEX 协议 | `npx tsx examples/multi_protocol_grpc.ts` | [multi_protocol_grpc.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/multi_protocol_grpc.ts) |
318
+ | 同时订阅所有 DEX 协议 | `npx tsx examples/multi_protocol_grpc.ts` | [multi_protocol_grpc.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/multi_protocol_grpc.ts) | `v0.5.20` |
307
319
  | **工具** | | |
308
- | 验证 onUpdate 同步错误不会打断 gRPC 流 | `npx tsx examples/grpc_onupdate_error_test.ts` | [grpc_onupdate_error_test.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/grpc_onupdate_error_test.ts) |
309
- | 按签名解析交易(`parseTransactionFromRpc`;非 gRPC)。在 `.env` 或环境中设置 `TX_SIGNATURE`。 | `npx tsx examples/parse_tx_by_signature.ts` | [parse_tx_by_signature.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/parse_tx_by_signature.ts) |
320
+ | 验证 onUpdate 同步错误不会打断 gRPC 流 | `npx tsx examples/grpc_onupdate_error_test.ts` | [grpc_onupdate_error_test.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/grpc_onupdate_error_test.ts) | `v0.5.20` |
321
+ | 按签名解析交易(`parseTransactionFromRpc`;非 gRPC)。在 `.env` 或环境中设置 `TX_SIGNATURE`。 | `npx tsx examples/parse_tx_by_signature.ts` | [parse_tx_by_signature.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/parse_tx_by_signature.ts) | `v0.5.20` |
310
322
 
311
323
  **`npm run` 别名**(与上表 ShredStream 行同一源码文件,每行一条):
312
324
 
@@ -350,3 +362,17 @@ MIT — https://github.com/0xfnzero/sol-parser-sdk-nodejs
350
362
  完整跨语言 API 对齐仍在进行;公开行为和支持边界见 [API 迁移说明](docs/USAGE.md#api-compatibility),使用方法见 examples 目录。
351
363
 
352
364
  PumpFun create/create_v2 的共享主网样本、重放方法和验证边界见 [验证说明](https://github.com/0xfnzero/sol-parser-sdk-golang/tree/main/validation/pumpfun_create_20261007)。
365
+
366
+ ### Pump ShredStream 离线回归
367
+
368
+ 已同步路由意图事件、严格 ALT 缓存解析和本语言原生签名回放/SBF 模拟示例。运行命令、缓存 API、冻结数据来源与测试范围见 [examples/offline_bank/README.md](examples/offline_bank/README.md)。默认跳过账户未解析完整的指令;旧行为需显式使用 best-effort 入口。路由意图不等于已成交事件,解析热路径不调用 RPC。
369
+
370
+ ### 可重复的本地热路径基准
371
+
372
+ 运行 `npx tsx examples/hotpath_benchmark.ts`;可选第二个参数为 JSON
373
+ 配置路径。默认配置在 `examples/hotpath_benchmark.json`,可修改预热次数、
374
+ 样本数与批大小。固定工作负载覆盖真实签名的包装程序和 ALT 交易,分别测量
375
+ 完整账户解析与 wire 解码加解析。文件读取、配置及样例准备均在计时之外,
376
+ 计时循环无 RPC/网络请求。输出 p50/p95/p99 为每批折算的单交易微秒分布,
377
+ 包含调度和 GC 影响;这不是生产延迟或上链速度保证。比较时保持运行时、
378
+ 配置和主机负载一致,双方均需先预热。
@@ -1,8 +1,11 @@
1
+ import type { PumpRouteIntentEvent } from "../instr/pump_routes.js";
1
2
  import type { PumpFunPostCompleteBuyEvent, PumpFunSweepBondingCurveFeeEvent, PumpFunCompleteEvent, PumpSwapSweepPoolFeeEvent } from "../logs/pump_upgrade.js";
2
3
  import type { RawAccountSnapshotEvent, LiquidityAccountSnapshotEvent } from '../liquidity_snapshot.js';
3
4
  import type { EventMetadata } from "./metadata.js";
4
5
  /** 统一 DEX 事件:外部标签 JSON(单键对象);键名清单见 `scripts/dex-event-variant-names.json` */
5
6
  export type DexEvent = {
7
+ PumpRouteIntent: PumpRouteIntentEvent;
8
+ } | {
6
9
  PumpFunPostCompleteBuy: PumpFunPostCompleteBuyEvent;
7
10
  } | {
8
11
  PumpFunSweepBondingCurveFee: PumpFunSweepBondingCurveFeeEvent;
@@ -154,7 +154,7 @@ export declare function accountFilterFromProgramOwners(programIds: string[]): Ac
154
154
  */
155
155
  export declare function accountFilterMemcmp(offset: number, bytes: Uint8Array): SubscribeRequestFilterAccountsFilter;
156
156
  /** 事件类型过滤标签 */
157
- export type EventType = "AccountRawSnapshot" | "AccountLiquiditySnapshot" | "BlockMeta" | "RaydiumLaunchlabTrade" | "RaydiumLaunchlabPoolCreate" | "RaydiumLaunchlabMigrateAmm" | "PumpFunTrade" | "PumpFunBuy" | "PumpFunSell" | "PumpFunBuyExactSolIn" | "PumpFunCreate" | "PumpFunCreateV2" | "PumpFunComplete" | "PumpFunMigrate" | "PumpFeesCreateFeeSharingConfig" | "PumpFeesInitializeFeeConfig" | "PumpFeesResetFeeSharingConfig" | "PumpFeesRevokeFeeSharingAuthority" | "PumpFeesTransferFeeSharingAuthority" | "PumpFeesUpdateAdmin" | "PumpFeesUpdateFeeConfig" | "PumpFeesUpdateFeeShares" | "PumpFeesUpsertFeeTiers" | "PumpFunPostCompleteBuy" | "PumpFunSweepBondingCurveFee" | "PumpSwapSweepPoolFee" | "PumpFunMigrateBondingCurveCreator" | "PumpSwapTrade" | "PumpSwapBuy" | "PumpSwapSell" | "PumpSwapCreatePool" | "PumpSwapLiquidityAdded" | "PumpSwapLiquidityRemoved" | "RaydiumCpmmSwap" | "RaydiumCpmmDeposit" | "RaydiumCpmmWithdraw" | "RaydiumCpmmInitialize" | "RaydiumClmmSwap" | "RaydiumClmmCreatePool" | "RaydiumClmmOpenPosition" | "RaydiumClmmClosePosition" | "RaydiumClmmIncreaseLiquidity" | "RaydiumClmmDecreaseLiquidity" | "RaydiumClmmLiquidityChange" | "RaydiumClmmConfigChange" | "RaydiumClmmCreatePersonalPosition" | "RaydiumClmmLiquidityCalculate" | "RaydiumClmmOpenLimitOrder" | "RaydiumClmmIncreaseLimitOrder" | "RaydiumClmmDecreaseLimitOrder" | "RaydiumClmmSettleLimitOrder" | "RaydiumClmmUpdateRewardInfos" | "RaydiumClmmOpenPositionWithTokenExtNft" | "RaydiumClmmCollectFee" | "RaydiumAmmV4Swap" | "RaydiumAmmV4Deposit" | "RaydiumAmmV4Withdraw" | "RaydiumAmmV4Initialize2" | "RaydiumAmmV4WithdrawPnl" | "OrcaWhirlpoolSwap" | "OrcaWhirlpoolLiquidityIncreased" | "OrcaWhirlpoolLiquidityDecreased" | "OrcaWhirlpoolPoolInitialized" | "MeteoraPoolsSwap" | "MeteoraPoolsAddLiquidity" | "MeteoraPoolsRemoveLiquidity" | "MeteoraPoolsBootstrapLiquidity" | "MeteoraPoolsPoolCreated" | "MeteoraPoolsSetPoolFees" | "MeteoraDammV2Swap" | "MeteoraDammV2AddLiquidity" | "MeteoraDammV2RemoveLiquidity" | "MeteoraDammV2InitializePool" | "MeteoraDammV2CreatePosition" | "MeteoraDammV2ClaimPositionFee" | "MeteoraDammV2ClaimReward" | "MeteoraDlmmClaimReward" | "MeteoraDammV2ClosePosition" | "MeteoraDammV2UpdateDelegatePermission" | "MeteoraDammV2WithdrawDeadLiquidityReward" | "MeteoraDammV2WithdrawIneligibleReward" | "MeteoraDammV2UpdateRewardFunder" | "MeteoraDammV2UpdateRewardDuration" | "MeteoraDammV2InitializeReward" | "MeteoraDammV2FundReward" | "MeteoraDammV2CreateConfig" | "MeteoraDammV2CreateDynamicConfig" | "MeteoraDbcSwap" | "MeteoraDbcInitializePool" | "MeteoraDbcCurveComplete" | "MeteoraDlmmSwap" | "MeteoraDlmmAddLiquidity" | "MeteoraDlmmRemoveLiquidity" | "MeteoraDlmmInitializePool" | "MeteoraDlmmInitializeBinArray" | "MeteoraDlmmCreatePosition" | "MeteoraDlmmClosePosition" | "MeteoraDlmmClaimFee" | "TokenAccount" | "TokenInfo" | "NonceAccount" | "AccountPumpFunGlobal" | "AccountPumpFunBondingCurve" | "AccountPumpFunFeeConfig" | "AccountPumpFunSharingConfig" | "AccountPumpFunGlobalVolumeAccumulator" | "AccountPumpFunUserVolumeAccumulator" | "AccountPumpSwapGlobalConfig" | "AccountPumpSwapPool" | "AccountRaydiumClmmAmmConfig" | "AccountRaydiumClmmPoolState" | "AccountRaydiumClmmTickArrayState" | "AccountRaydiumCpmmAmmConfig" | "AccountRaydiumCpmmPoolState" | "AccountOrcaWhirlpool" | "AccountOrcaPosition" | "AccountOrcaTickArray" | "AccountOrcaFeeTier" | "AccountOrcaWhirlpoolsConfig";
157
+ export type EventType = "PumpRouteIntent" | "AccountRawSnapshot" | "AccountLiquiditySnapshot" | "BlockMeta" | "RaydiumLaunchlabTrade" | "RaydiumLaunchlabPoolCreate" | "RaydiumLaunchlabMigrateAmm" | "PumpFunTrade" | "PumpFunBuy" | "PumpFunSell" | "PumpFunBuyExactSolIn" | "PumpFunCreate" | "PumpFunCreateV2" | "PumpFunComplete" | "PumpFunMigrate" | "PumpFeesCreateFeeSharingConfig" | "PumpFeesInitializeFeeConfig" | "PumpFeesResetFeeSharingConfig" | "PumpFeesRevokeFeeSharingAuthority" | "PumpFeesTransferFeeSharingAuthority" | "PumpFeesUpdateAdmin" | "PumpFeesUpdateFeeConfig" | "PumpFeesUpdateFeeShares" | "PumpFeesUpsertFeeTiers" | "PumpFunPostCompleteBuy" | "PumpFunSweepBondingCurveFee" | "PumpSwapSweepPoolFee" | "PumpFunMigrateBondingCurveCreator" | "PumpSwapTrade" | "PumpSwapBuy" | "PumpSwapSell" | "PumpSwapCreatePool" | "PumpSwapLiquidityAdded" | "PumpSwapLiquidityRemoved" | "RaydiumCpmmSwap" | "RaydiumCpmmDeposit" | "RaydiumCpmmWithdraw" | "RaydiumCpmmInitialize" | "RaydiumClmmSwap" | "RaydiumClmmCreatePool" | "RaydiumClmmOpenPosition" | "RaydiumClmmClosePosition" | "RaydiumClmmIncreaseLiquidity" | "RaydiumClmmDecreaseLiquidity" | "RaydiumClmmLiquidityChange" | "RaydiumClmmConfigChange" | "RaydiumClmmCreatePersonalPosition" | "RaydiumClmmLiquidityCalculate" | "RaydiumClmmOpenLimitOrder" | "RaydiumClmmIncreaseLimitOrder" | "RaydiumClmmDecreaseLimitOrder" | "RaydiumClmmSettleLimitOrder" | "RaydiumClmmUpdateRewardInfos" | "RaydiumClmmOpenPositionWithTokenExtNft" | "RaydiumClmmCollectFee" | "RaydiumAmmV4Swap" | "RaydiumAmmV4Deposit" | "RaydiumAmmV4Withdraw" | "RaydiumAmmV4Initialize2" | "RaydiumAmmV4WithdrawPnl" | "OrcaWhirlpoolSwap" | "OrcaWhirlpoolLiquidityIncreased" | "OrcaWhirlpoolLiquidityDecreased" | "OrcaWhirlpoolPoolInitialized" | "MeteoraPoolsSwap" | "MeteoraPoolsAddLiquidity" | "MeteoraPoolsRemoveLiquidity" | "MeteoraPoolsBootstrapLiquidity" | "MeteoraPoolsPoolCreated" | "MeteoraPoolsSetPoolFees" | "MeteoraDammV2Swap" | "MeteoraDammV2AddLiquidity" | "MeteoraDammV2RemoveLiquidity" | "MeteoraDammV2InitializePool" | "MeteoraDammV2CreatePosition" | "MeteoraDammV2ClaimPositionFee" | "MeteoraDammV2ClaimReward" | "MeteoraDlmmClaimReward" | "MeteoraDammV2ClosePosition" | "MeteoraDammV2UpdateDelegatePermission" | "MeteoraDammV2WithdrawDeadLiquidityReward" | "MeteoraDammV2WithdrawIneligibleReward" | "MeteoraDammV2UpdateRewardFunder" | "MeteoraDammV2UpdateRewardDuration" | "MeteoraDammV2InitializeReward" | "MeteoraDammV2FundReward" | "MeteoraDammV2CreateConfig" | "MeteoraDammV2CreateDynamicConfig" | "MeteoraDbcSwap" | "MeteoraDbcInitializePool" | "MeteoraDbcCurveComplete" | "MeteoraDlmmSwap" | "MeteoraDlmmAddLiquidity" | "MeteoraDlmmRemoveLiquidity" | "MeteoraDlmmInitializePool" | "MeteoraDlmmInitializeBinArray" | "MeteoraDlmmCreatePosition" | "MeteoraDlmmClosePosition" | "MeteoraDlmmClaimFee" | "TokenAccount" | "TokenInfo" | "NonceAccount" | "AccountPumpFunGlobal" | "AccountPumpFunBondingCurve" | "AccountPumpFunFeeConfig" | "AccountPumpFunSharingConfig" | "AccountPumpFunGlobalVolumeAccumulator" | "AccountPumpFunUserVolumeAccumulator" | "AccountPumpSwapGlobalConfig" | "AccountPumpSwapPool" | "AccountRaydiumClmmAmmConfig" | "AccountRaydiumClmmPoolState" | "AccountRaydiumClmmTickArrayState" | "AccountRaydiumCpmmAmmConfig" | "AccountRaydiumCpmmPoolState" | "AccountOrcaWhirlpool" | "AccountOrcaPosition" | "AccountOrcaTickArray" | "AccountOrcaFeeTier" | "AccountOrcaWhirlpoolsConfig";
158
158
  /** 与 Rust `grpc::EventType`(由 `StreamingEventType` 导出)一致 */
159
159
  export type StreamingEventType = EventType;
160
160
  /** 所有事件类型列表 */
@@ -30,6 +30,7 @@ exports.eventTypeFilterIncludesRaydiumAmmV4 = eventTypeFilterIncludesRaydiumAmmV
30
30
  exports.eventTypeFilterIncludesOrcaWhirlpool = eventTypeFilterIncludesOrcaWhirlpool;
31
31
  exports.eventTypeFilterIncludesRaydiumLaunchlab = eventTypeFilterIncludesRaydiumLaunchlab;
32
32
  exports.eventTypeFilterAllowsInstructionParsing = eventTypeFilterAllowsInstructionParsing;
33
+ const pump_routes_js_1 = require("../instr/pump_routes.js");
33
34
  const metadata_js_1 = require("../core/metadata.js");
34
35
  function defaultClientConfig() {
35
36
  return {
@@ -260,6 +261,7 @@ exports.ALL_EVENT_TYPES = [
260
261
  "PumpFunPostCompleteBuy",
261
262
  "PumpFunSweepBondingCurveFee",
262
263
  "PumpSwapSweepPoolFee",
264
+ "PumpRouteIntent",
263
265
  ];
264
266
  const ALL_EVENT_TYPE_SET = new Set(exports.ALL_EVENT_TYPES);
265
267
  const PUMPFUN_BUY_FAMILY = ["PumpFunBuy", "PumpFunBuyExactSolIn"];
@@ -390,6 +392,7 @@ const RAYDIUM_LAUNCHLAB_FILTER_TYPES = [
390
392
  "RaydiumLaunchlabMigrateAmm",
391
393
  ];
392
394
  const INSTRUCTION_EVENT_TYPES = [
395
+ "PumpRouteIntent",
393
396
  ...PUMPFUN_FILTER_TYPES,
394
397
  ...PUMP_FEES_EVENT_TYPES,
395
398
  ...PUMPSWAP_FILTER_TYPES,
@@ -436,6 +439,8 @@ function eventTypeFromDexEvent(event) {
436
439
  return ALL_EVENT_TYPE_SET.has(variant) ? variant : null;
437
440
  }
438
441
  function eventTypeFilterShouldIncludeDexEvent(filter, event) {
442
+ if ("PumpRouteIntent" in event)
443
+ return (0, pump_routes_js_1.allowsPumpRoute)(filter, event.PumpRouteIntent.program);
439
444
  const eventType = eventTypeFromDexEvent(event);
440
445
  return eventType === null || filter.shouldInclude(eventType);
441
446
  }
package/dist/index.d.ts CHANGED
@@ -48,7 +48,7 @@ export { connectYellowstoneGeyser, defaultGeyserConnectConfig, geyserGrpcChannel
48
48
  /** 与 Rust `sol_parser_sdk::grpc::event_parser` 模块对应 */
49
49
  export * as event_parser from "./grpc/event_parser.js";
50
50
  export { connectYellowstoneGeyser as connect_yellowstone_geyser, defaultGeyserConnectConfig as default_geyser_connect_config, geyserGrpcChannelOptions as geyser_grpc_channel_options, } from "./grpc/geyser_connect.js";
51
- export { ShredStreamClient, ShredEventQueue, dexEventsFromShredWasmTx, dexEventsFromShredWasmTxWithFullKeys, fullAccountKeyStringsFromShredTx, loadAddressLookupTableAccounts, bincodeVecEntryCount, decodeEntriesBincodeFlat, decodeEntriesBincodeNested, decodeShredstreamEntriesBincode, wireBytesToShredWasmTx, type ShredStreamReceiveStats, type ShredWasmTx, type ShredWasmCompiledIx, type ShredStreamConfig, type DecodedWireTransaction, defaultShredStreamConfig, lowLatencyShredStreamConfig, highThroughputShredStreamConfig, type SubscribeEntriesRequest, type ShredstreamEntryMessage, } from "./shredstream/index.js";
51
+ export { ShredStreamClient, ShredEventQueue, dexEventsFromShredWasmTx, dexEventsFromShredWasmTxBestEffort, dexEventsFromShredWasmTxWithLoadedAddresses, dexEventsFromShredWasmTxWithFullKeys, fullAccountKeyStringsFromShredTx, loadAddressLookupTableAccounts, bincodeVecEntryCount, decodeEntriesBincodeFlat, decodeEntriesBincodeNested, decodeShredstreamEntriesBincode, wireBytesToShredWasmTx, type ShredStreamReceiveStats, type ShredWasmTx, type ShredWasmCompiledIx, type ShredStreamConfig, type DecodedWireTransaction, defaultShredStreamConfig, lowLatencyShredStreamConfig, highThroughputShredStreamConfig, type SubscribeEntriesRequest, type ShredstreamEntryMessage, } from "./shredstream/index.js";
52
52
  export { defaultShredStreamConfig as default_shred_stream_config, lowLatencyShredStreamConfig as low_latency_shred_stream_config, highThroughputShredStreamConfig as high_throughput_shred_stream_config, } from "./shredstream/index.js";
53
53
  export { decodeWireTransaction, type WireMessage, type WireInstruction, type DecodedWireTransaction as NativeWireTransaction } from './wire_transaction.js';
54
54
  export * from './transaction_route.js';
@@ -59,3 +59,4 @@ export { parseBlockMetaUpdate } from "./grpc/block_meta.js";
59
59
  export { buildSubscribeRequestWithEventFilter } from "./grpc/subscribe_builder.js";
60
60
  export type { LaunchLabPoolCreateEvent, StonkFunPoolCreateEvent, LaunchLabTradeEvent, StonkFunTradeEvent, } from "./core/dex_event.js";
61
61
  export * from "./logs/pump_upgrade.js";
62
+ export * from "./instr/pump_routes.js";
package/dist/index.js CHANGED
@@ -40,7 +40,7 @@ exports.pubkeyBytesToBs58 = exports.grpcTxIndexFromInfo = exports.parseDexEvents
40
40
  exports.RAYDIUM_CPMM_PROGRAM_ID = exports.RAYDIUM_LAUNCHLAB_PROGRAM_ID = exports.PUMP_FEES_PROGRAM_ID = exports.PUMPSWAP_FEES_PROGRAM_ID = exports.PUMPSWAP_PROGRAM_ID = exports.PUMPFUN_PROGRAM_ID = exports.PROTOCOL_PROGRAM_IDS = exports.all_event_types = exports.ALL_EVENT_TYPES = exports.eventTypeFilterAllowsInstructionParsing = exports.eventTypeFilterIncludesPumpFees = exports.eventTypeFilterIncludesRaydiumLaunchlab = exports.eventTypeFilterIncludesOrcaWhirlpool = exports.eventTypeFilterIncludesRaydiumAmmV4 = exports.eventTypeFilterIncludesRaydiumCpmm = exports.eventTypeFilterIncludesRaydiumClmm = exports.eventTypeFilterIncludesMeteoraDlmm = exports.eventTypeFilterIncludesMeteoraPools = exports.eventTypeFilterIncludesMeteoraDbc = exports.eventTypeFilterIncludesMeteoraDammV2 = exports.eventTypeFilterIncludesPumpswap = exports.eventTypeFilterIncludesPumpfun = exports.eventTypeFilterExclude = exports.eventTypeFilterIncludeOnly = exports.accountFilterMemcmp = exports.accountFilterFromProgramOwners = exports.slotFilterMaxSlot = exports.slotFilterMinSlot = exports.newSlotFilter = exports.newAccountFilter = exports.transactionFilterFromProgramIds = exports.newTransactionFilter = exports.highThroughputClientConfig = exports.lowLatencyClientConfig = exports.defaultClientConfig = exports.try_yellowstone_signature = exports.collect_watch_transfer_counterparty_pairs = exports.spl_token_counterparty_by_owner = exports.token_balance_raw_amount = exports.heuristic_sol_counterparties_for_watched_keys = exports.lamport_balance_deltas = exports.collect_account_keys_bs58 = exports.pubkey_bytes_to_bs58 = exports.tryYellowstoneSignature = exports.collectWatchTransferCounterpartyPairs = exports.splTokenCounterpartyByOwner = exports.tokenBalanceRawAmount = exports.heuristicSolCounterpartiesForWatchedKeys = exports.lamportBalanceDeltas = exports.collectAccountKeysBs58 = void 0;
41
41
  exports.discriminatorToProtocol = exports.discriminator_to_name = exports.discriminatorToName = exports.parse_log_unified = exports.parse_log_optimized = exports.parse_meteora_dlmm_log = exports.parse_meteora_damm_log = exports.parseProgramCompleteInfo = exports.parseLogUnified = exports.parseLogOptimizedWithProgramId = exports.parseLogOptimized = exports.parseInvokeInfo = exports.build_subscribe_transaction_filters_named = exports.build_subscribe_request_with_commitment = exports.build_subscribe_request = exports.CommitmentLevel = exports.buildSubscribeTransactionFiltersNamed = exports.buildSubscribeRequestWithCommitment = exports.buildSubscribeRequest = exports.exclude_types = exports.include_only = exports.event_type_filter_exclude = exports.event_type_filter_include_only = exports.account_filter_memcmp = exports.account_filter_from_program_owners = exports.slot_filter_max_slot = exports.slot_filter_min_slot = exports.new_slot_filter = exports.new_account_filter = exports.transaction_filter_from_program_ids = exports.new_transaction_filter = exports.high_throughput_client_config = exports.low_latency_client_config = exports.default_client_config = exports.account_filter_for_protocols = exports.transaction_filter_for_protocol_accounts = exports.transaction_filter_for_protocols = exports.get_program_ids_for_protocols = exports.protocol_program_ids = exports.accountFilterForProtocols = exports.transactionFilterForProtocolAccounts = exports.transactionFilterForProtocols = exports.getProgramIdsForProtocols = exports.METEORA_DBC_PROGRAM_ID = exports.METEORA_DLMM_PROGRAM_ID = exports.METEORA_DAMM_V2_PROGRAM_ID = exports.METEORA_POOLS_PROGRAM_ID = exports.ORCA_WHIRLPOOL_PROGRAM_ID = exports.RAYDIUM_AMM_V4_PROGRAM_ID = exports.RAYDIUM_CLMM_PROGRAM_ID = void 0;
42
42
  exports.event_parser = exports.geyserGrpcChannelOptions = exports.defaultGeyserConnectConfig = exports.connectYellowstoneGeyser = exports.YellowstoneGrpc = exports.programIds = exports.parse_pump_fees_instruction = exports.parse_meteora_pools_instruction = exports.parse_meteora_dlmm_instruction = exports.parse_meteora_damm_instruction = exports.parse_pumpswap_instruction = exports.parse_pumpfun_instruction = exports.parse_instruction_unified = exports.parsePumpFeesInstruction = exports.parseMeteoraPoolsInstruction = exports.parseMeteoraDlmmInstruction = exports.parseMeteoraDammInstruction = exports.parsePumpswapInstruction = exports.parsePumpfunInstruction = exports.parseInstructionUnified = exports.user_wallet_pubkey_for_onchain_account = exports.rpc_resolve_user_wallet_pubkey = exports.parse_pumpswap_pool = exports.parse_pumpswap_global_config = exports.parse_pumpfun_global = exports.parse_token_account = exports.parse_nonce_account = exports.parse_account_unified = exports.rpcResolveUserWalletPubkey = exports.userWalletPubkeyForOnchainAccount = exports.hasDiscriminator = exports.isPoolAccount = exports.isGlobalConfigAccount = exports.parsePumpswapAccount = exports.parsePumpswapPool = exports.parsePumpswapGlobalConfig = exports.isPumpfunGlobalAccount = exports.parsePumpfunAccount = exports.parsePumpfunGlobal = exports.parseTokenAccount = exports.isNonceAccount = exports.parseNonceAccount = exports.parseAccountUnified = exports.u64leDiscriminator = exports.PUMPSWAP_DISC = exports.PROGRAM_LOG_DISC = exports.parseMeteoraDammLog = exports.lookup_discriminator = exports.lookupDiscriminator = exports.discriminator_to_protocol = void 0;
43
- exports.buildSubscribeRequestWithEventFilter = exports.parseBlockMetaUpdate = exports.analyzeSimulationRoutes = exports.decodeWireTransaction = exports.high_throughput_shred_stream_config = exports.low_latency_shred_stream_config = exports.default_shred_stream_config = exports.highThroughputShredStreamConfig = exports.lowLatencyShredStreamConfig = exports.defaultShredStreamConfig = exports.wireBytesToShredWasmTx = exports.decodeShredstreamEntriesBincode = exports.decodeEntriesBincodeNested = exports.decodeEntriesBincodeFlat = exports.bincodeVecEntryCount = exports.loadAddressLookupTableAccounts = exports.fullAccountKeyStringsFromShredTx = exports.dexEventsFromShredWasmTxWithFullKeys = exports.dexEventsFromShredWasmTx = exports.ShredEventQueue = exports.ShredStreamClient = exports.geyser_grpc_channel_options = exports.default_geyser_connect_config = exports.connect_yellowstone_geyser = void 0;
43
+ exports.buildSubscribeRequestWithEventFilter = exports.parseBlockMetaUpdate = exports.analyzeSimulationRoutes = exports.decodeWireTransaction = exports.high_throughput_shred_stream_config = exports.low_latency_shred_stream_config = exports.default_shred_stream_config = exports.highThroughputShredStreamConfig = exports.lowLatencyShredStreamConfig = exports.defaultShredStreamConfig = exports.wireBytesToShredWasmTx = exports.decodeShredstreamEntriesBincode = exports.decodeEntriesBincodeNested = exports.decodeEntriesBincodeFlat = exports.bincodeVecEntryCount = exports.loadAddressLookupTableAccounts = exports.fullAccountKeyStringsFromShredTx = exports.dexEventsFromShredWasmTxWithFullKeys = exports.dexEventsFromShredWasmTxWithLoadedAddresses = exports.dexEventsFromShredWasmTxBestEffort = exports.dexEventsFromShredWasmTx = exports.ShredEventQueue = exports.ShredStreamClient = exports.geyser_grpc_channel_options = exports.default_geyser_connect_config = exports.connect_yellowstone_geyser = void 0;
44
44
  var constants_js_1 = require("./common/constants.js");
45
45
  Object.defineProperty(exports, "DEFAULT_CHANNEL_SIZE", { enumerable: true, get: function () { return constants_js_1.DEFAULT_CHANNEL_SIZE; } });
46
46
  Object.defineProperty(exports, "DEFAULT_CONNECT_TIMEOUT", { enumerable: true, get: function () { return constants_js_1.DEFAULT_CONNECT_TIMEOUT; } });
@@ -290,6 +290,8 @@ var index_js_1 = require("./shredstream/index.js");
290
290
  Object.defineProperty(exports, "ShredStreamClient", { enumerable: true, get: function () { return index_js_1.ShredStreamClient; } });
291
291
  Object.defineProperty(exports, "ShredEventQueue", { enumerable: true, get: function () { return index_js_1.ShredEventQueue; } });
292
292
  Object.defineProperty(exports, "dexEventsFromShredWasmTx", { enumerable: true, get: function () { return index_js_1.dexEventsFromShredWasmTx; } });
293
+ Object.defineProperty(exports, "dexEventsFromShredWasmTxBestEffort", { enumerable: true, get: function () { return index_js_1.dexEventsFromShredWasmTxBestEffort; } });
294
+ Object.defineProperty(exports, "dexEventsFromShredWasmTxWithLoadedAddresses", { enumerable: true, get: function () { return index_js_1.dexEventsFromShredWasmTxWithLoadedAddresses; } });
293
295
  Object.defineProperty(exports, "dexEventsFromShredWasmTxWithFullKeys", { enumerable: true, get: function () { return index_js_1.dexEventsFromShredWasmTxWithFullKeys; } });
294
296
  Object.defineProperty(exports, "fullAccountKeyStringsFromShredTx", { enumerable: true, get: function () { return index_js_1.fullAccountKeyStringsFromShredTx; } });
295
297
  Object.defineProperty(exports, "loadAddressLookupTableAccounts", { enumerable: true, get: function () { return index_js_1.loadAddressLookupTableAccounts; } });
@@ -317,3 +319,4 @@ Object.defineProperty(exports, "parseBlockMetaUpdate", { enumerable: true, get:
317
319
  var subscribe_builder_js_3 = require("./grpc/subscribe_builder.js");
318
320
  Object.defineProperty(exports, "buildSubscribeRequestWithEventFilter", { enumerable: true, get: function () { return subscribe_builder_js_3.buildSubscribeRequestWithEventFilter; } });
319
321
  __exportStar(require("./logs/pump_upgrade.js"), exports);
322
+ __exportStar(require("./instr/pump_routes.js"), exports);
@@ -0,0 +1,27 @@
1
+ /** Program-bound wire intents. No RPC, fills, balances or reserves are inferred. */
2
+ import type { EventMetadata } from '../core/metadata.js';
3
+ import type { EventTypeFilter } from '../grpc/types.js';
4
+ export interface PumpRouteHop {
5
+ base_mint: string;
6
+ quote_mint: string;
7
+ venue: string;
8
+ base_vault: string;
9
+ quote_vault: string;
10
+ }
11
+ export interface PumpRouteIntentEvent {
12
+ metadata: EventMetadata;
13
+ kind: 'MultiHopSwap' | 'MultiHopCurveSwap' | 'RapidBuy' | 'BuyPumpDelta';
14
+ program: string;
15
+ instruction_index: number;
16
+ user: string;
17
+ input_account: string;
18
+ output_account: string;
19
+ amount_in: bigint | null;
20
+ min_amount_out: bigint | null;
21
+ hops: PumpRouteHop[];
22
+ instruction_data: number[];
23
+ }
24
+ export declare function mayParsePumpRoute(program: string, data: Uint8Array): boolean;
25
+ export declare function allowsPumpRoute(filter: EventTypeFilter | undefined, program: string): boolean;
26
+ export declare function pumpMultiHopArgs(program: string, data: Uint8Array, a: readonly string[]): [bigint, bigint] | null;
27
+ export declare function parsePumpRoute(program: string, data: Uint8Array, a: readonly string[], metadata: EventMetadata, index: number, filter?: EventTypeFilter): PumpRouteIntentEvent | null;
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mayParsePumpRoute = mayParsePumpRoute;
4
+ exports.allowsPumpRoute = allowsPumpRoute;
5
+ exports.pumpMultiHopArgs = pumpMultiHopArgs;
6
+ exports.parsePumpRoute = parsePumpRoute;
7
+ const PUMP = '6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P', AMM = 'pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA', RAPID = 'rapidV5DAKtecYzetwCNoxXWHpezjeg4hGt9BGiVcGW', DELTA = 'J7pourVwqP1VtRNBiFNqbdGxwkx7ta2LHAURURRRJqmd', TOKEN = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', TOKEN22 = 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb', SYSTEM = '11111111111111111111111111111111', ATA = 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL', GLOBAL = '4wTV1YmiEkRvAtNtsSGPtUrqRYQMe5SKy2uB4Jjaxnjf', EVENT = 'Ce6TQqeHC9p8KetsN6JsjHK7UTZk7nasjjnr7XxXp9F1', FEES = 'pfeeUxB6jkeY1Hxd7CsFCAjcbHA9rWtchMGdZ6VojVZ';
8
+ function matches(data, at, bytes) { return bytes.every((v, i) => data[at + i] === v); }
9
+ const MULTI = [43, 100, 73, 19, 233, 246, 111, 148], CURVE = [225, 154, 117, 22, 215, 86, 246, 103];
10
+ function mayParsePumpRoute(program, data) {
11
+ return (program === AMM && matches(data, 0, MULTI)) || (program === PUMP && matches(data, 0, CURVE))
12
+ || (program === DELTA && data.length === 28 && matches(data, 0, [122, 28, 94, 147, 180, 45, 240, 97]))
13
+ || (program === RAPID && data.length === 41 && data[0] === 0 && matches(data, 9, [1, 0, 0, 27, 15, 14, 8, 24]) && matches(data, 17, [194, 171, 28, 70, 104, 77, 91, 47]) && matches(data, 25, Array(8).fill(0)));
14
+ }
15
+ function allowsPumpRoute(filter, program) {
16
+ if (!filter)
17
+ return true;
18
+ const excluded = filter.exclude_types ?? [];
19
+ if (excluded.includes('PumpRouteIntent') || excluded.includes('PumpFunTrade') || (program === AMM && excluded.includes('PumpSwapTrade')))
20
+ return false;
21
+ const included = filter.include_only;
22
+ return included ? included.includes('PumpRouteIntent') || included.includes('PumpFunTrade') || (program === AMM && included.includes('PumpSwapTrade')) : filter.shouldInclude('PumpRouteIntent');
23
+ }
24
+ function context(a, pairs) { return Object.entries(pairs).every(([i, v]) => a[Number(i)] === v); }
25
+ function pumpMultiHopArgs(program, data, a) {
26
+ if (program !== AMM || data.length !== 24 || !matches(data, 0, MULTI) || a.length < 21 || (a.length - 16) % 5 || !context(a, { 7: TOKEN, 8: TOKEN22, 9: SYSTEM, 11: AMM, 12: PUMP }))
27
+ return null;
28
+ const d = new DataView(data.buffer, data.byteOffset, data.byteLength), amount = d.getBigUint64(8, true);
29
+ return amount ? [amount, d.getBigUint64(16, true)] : null;
30
+ }
31
+ function parsePumpRoute(program, data, a, metadata, index, filter) {
32
+ if (!mayParsePumpRoute(program, data) || !allowsPumpRoute(filter, program))
33
+ return null;
34
+ const d = new DataView(data.buffer, data.byteOffset, data.byteLength), u = (at) => d.getBigUint64(at, true);
35
+ let kind, fixed, user, input, output, amount, minimum;
36
+ if (program === AMM) {
37
+ const args = pumpMultiHopArgs(program, data, a);
38
+ if (!args)
39
+ return null;
40
+ [kind, fixed, user, input, output, amount, minimum] = ['MultiHopSwap', 16, 0, 1, 2, ...args];
41
+ }
42
+ else if (program === PUMP) {
43
+ if (data.length < 20)
44
+ return null;
45
+ const count = d.getUint32(16, true);
46
+ if (!count || data.length !== 20 + count || a.length !== 13 + count * 5 || !context(a, { 8: TOKEN, 9: TOKEN22, 10: SYSTEM, 11: EVENT, 12: PUMP }))
47
+ return null;
48
+ [kind, fixed, user, input, output, amount, minimum] = ['MultiHopCurveSwap', 13, 3, 5, 6, u(8), null];
49
+ }
50
+ else if (program === RAPID) {
51
+ if (a.length !== 33 || a[0] !== a[19] || a[2] !== a[8] || ![TOKEN, TOKEN22].includes(a[9]) || !context(a, { 3: TOKEN, 4: SYSTEM, 5: PUMP, 6: GLOBAL, 10: TOKEN, 11: ATA, 29: FEES, 30: SYSTEM, 31: EVENT, 32: PUMP }))
52
+ return null;
53
+ [kind, fixed, user, input, output, amount, minimum] = ['RapidBuy', 0, 0, 21, 20, u(1), u(33)];
54
+ }
55
+ else {
56
+ if (a.length !== 30 || a[0] !== a[14] || ![TOKEN, TOKEN22].includes(a[4]) || ![TOKEN, TOKEN22].includes(a[5]) || !context(a, { 1: GLOBAL, 6: ATA, 24: FEES, 25: SYSTEM, 26: EVENT, 27: PUMP }))
57
+ return null;
58
+ [kind, fixed, user, input, output, amount, minimum] = ['BuyPumpDelta', 0, 0, 16, 15, null, null];
59
+ }
60
+ if (amount === 0n)
61
+ return null;
62
+ const hop = (h) => ({ base_mint: h[0], quote_mint: h[1], venue: h[2], base_vault: h[3], quote_vault: h[4] });
63
+ const hops = [];
64
+ if (fixed) {
65
+ for (let i = fixed; i < a.length; i += 5)
66
+ hops.push(hop(a.slice(i, i + 5)));
67
+ }
68
+ else
69
+ hops.push(hop((program === RAPID ? [7, 2, 16, 17, 18] : [2, 3, 11, 12, 13]).map(i => a[i])));
70
+ return { metadata, kind, program, instruction_index: index, user: a[user], input_account: a[input], output_account: a[output], amount_in: amount, min_amount_out: minimum, hops, instruction_data: Array.from(data) };
71
+ }
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.pumpUpgradeEventType = pumpUpgradeEventType;
4
4
  exports.parsePumpUpgradeEvent = parsePumpUpgradeEvent;
5
5
  exports.decodePumpMultiHopIntent = decodePumpMultiHopIntent;
6
+ const pump_routes_js_1 = require("../instr/pump_routes.js");
6
7
  const binary_js_1 = require("../util/binary.js");
7
8
  function pumpUpgradeEventType(disc, programId) {
8
9
  if (disc === 18146529233607700591n &&
@@ -99,15 +100,10 @@ function parsePumpUpgradeEvent(disc, data, metadata, programId) {
99
100
  }
100
101
  /** Intent amounts are limits, not execution. Each hop emits its own actual trade. */
101
102
  function decodePumpMultiHopIntent(program, data, accounts) {
102
- if (program !== "pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA" ||
103
- data.length !== 24 ||
104
- (0, binary_js_1.readU64LE)(data, 0) !== 10696039120939607083n ||
105
- accounts.length < 21 ||
106
- (accounts.length - 16) % 5 !== 0)
107
- return null;
108
- const amountIn = (0, binary_js_1.readU64LE)(data, 8), minAmountOut = (0, binary_js_1.readU64LE)(data, 16);
109
- if (!amountIn || !minAmountOut)
103
+ const args = (0, pump_routes_js_1.pumpMultiHopArgs)(program, data, accounts);
104
+ if (!args)
110
105
  return null;
106
+ const [amountIn, minAmountOut] = args;
111
107
  const hops = [];
112
108
  for (let i = 16; i < accounts.length; i += 5)
113
109
  hops.push({
@@ -5,12 +5,12 @@
5
5
  * - ALT 仅使用预热缓存;启用缓存后 miss 会跳过该交易并记录 altCacheMissTransactions,不回放
6
6
  * - 无 inner instructions,无法 CPI 解析
7
7
  * - 无 block_time
8
- * - 无交易日志(program logs);客户端使用外层指令解析。未配置 ALT 缓存时保留静态账户 best-effort 行为。
8
+ * - 无交易日志(program logs);客户端使用外层指令解析。未配置 ALT 缓存时仅解析账户完整的静态指令。
9
9
  * - `metadata.tx_index` 为**单条 gRPC `Entry` 消息内**跨所有 Solana `Entry` 分组的连续下标(与 golang `shredstream_entries` 扁平 `ti` 对齐),非 slot 级全局序号
10
10
  */
11
11
  export { type ShredStreamConfig, defaultShredStreamConfig, lowLatencyShredStreamConfig, highThroughputShredStreamConfig, } from "./config.js";
12
12
  export { ShredStreamClient, ShredEventQueue, type ShredStreamReceiveStats, } from "./client.js";
13
- export { dexEventsFromShredWasmTx, dexEventsFromShredWasmTxWithFullKeys, type ShredWasmTx, type ShredWasmCompiledIx, } from "./instruction_parse.js";
13
+ export { dexEventsFromShredWasmTx, dexEventsFromShredWasmTxBestEffort, dexEventsFromShredWasmTxWithLoadedAddresses, dexEventsFromShredWasmTxWithFullKeys, type ShredWasmTx, type ShredWasmCompiledIx, } from "./instruction_parse.js";
14
14
  export { fullAccountKeyStringsFromShredTx, loadAddressLookupTableAccounts } from "./alt_lookup.js";
15
15
  export type { SubscribeEntriesRequest, ShredstreamEntryMessage } from "./proto_types.js";
16
16
  export { bincodeVecEntryCount, decodeEntriesBincodeFlat, decodeEntriesBincodeNested, decodeShredstreamEntriesBincode, type DecodedWireTransaction, } from "./entries_decode.js";
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AddressLookupTableCache = exports.wireBytesToShredWasmTx = exports.decodeShredstreamEntriesBincode = exports.decodeEntriesBincodeNested = exports.decodeEntriesBincodeFlat = exports.bincodeVecEntryCount = exports.loadAddressLookupTableAccounts = exports.fullAccountKeyStringsFromShredTx = exports.dexEventsFromShredWasmTxWithFullKeys = exports.dexEventsFromShredWasmTx = exports.ShredEventQueue = exports.ShredStreamClient = exports.highThroughputShredStreamConfig = exports.lowLatencyShredStreamConfig = exports.defaultShredStreamConfig = void 0;
3
+ exports.AddressLookupTableCache = exports.wireBytesToShredWasmTx = exports.decodeShredstreamEntriesBincode = exports.decodeEntriesBincodeNested = exports.decodeEntriesBincodeFlat = exports.bincodeVecEntryCount = exports.loadAddressLookupTableAccounts = exports.fullAccountKeyStringsFromShredTx = exports.dexEventsFromShredWasmTxWithFullKeys = exports.dexEventsFromShredWasmTxWithLoadedAddresses = exports.dexEventsFromShredWasmTxBestEffort = exports.dexEventsFromShredWasmTx = exports.ShredEventQueue = exports.ShredStreamClient = exports.highThroughputShredStreamConfig = exports.lowLatencyShredStreamConfig = exports.defaultShredStreamConfig = void 0;
4
4
  /**
5
5
  * Jito ShredStream 超低延迟订阅(与 Rust `sol-parser-sdk::shredstream` 对齐)。
6
6
  *
@@ -8,7 +8,7 @@ exports.AddressLookupTableCache = exports.wireBytesToShredWasmTx = exports.decod
8
8
  * - ALT 仅使用预热缓存;启用缓存后 miss 会跳过该交易并记录 altCacheMissTransactions,不回放
9
9
  * - 无 inner instructions,无法 CPI 解析
10
10
  * - 无 block_time
11
- * - 无交易日志(program logs);客户端使用外层指令解析。未配置 ALT 缓存时保留静态账户 best-effort 行为。
11
+ * - 无交易日志(program logs);客户端使用外层指令解析。未配置 ALT 缓存时仅解析账户完整的静态指令。
12
12
  * - `metadata.tx_index` 为**单条 gRPC `Entry` 消息内**跨所有 Solana `Entry` 分组的连续下标(与 golang `shredstream_entries` 扁平 `ti` 对齐),非 slot 级全局序号
13
13
  */
14
14
  var config_js_1 = require("./config.js");
@@ -20,6 +20,8 @@ Object.defineProperty(exports, "ShredStreamClient", { enumerable: true, get: fun
20
20
  Object.defineProperty(exports, "ShredEventQueue", { enumerable: true, get: function () { return client_js_1.ShredEventQueue; } });
21
21
  var instruction_parse_js_1 = require("./instruction_parse.js");
22
22
  Object.defineProperty(exports, "dexEventsFromShredWasmTx", { enumerable: true, get: function () { return instruction_parse_js_1.dexEventsFromShredWasmTx; } });
23
+ Object.defineProperty(exports, "dexEventsFromShredWasmTxBestEffort", { enumerable: true, get: function () { return instruction_parse_js_1.dexEventsFromShredWasmTxBestEffort; } });
24
+ Object.defineProperty(exports, "dexEventsFromShredWasmTxWithLoadedAddresses", { enumerable: true, get: function () { return instruction_parse_js_1.dexEventsFromShredWasmTxWithLoadedAddresses; } });
23
25
  Object.defineProperty(exports, "dexEventsFromShredWasmTxWithFullKeys", { enumerable: true, get: function () { return instruction_parse_js_1.dexEventsFromShredWasmTxWithFullKeys; } });
24
26
  var alt_lookup_js_1 = require("./alt_lookup.js");
25
27
  Object.defineProperty(exports, "fullAccountKeyStringsFromShredTx", { enumerable: true, get: function () { return alt_lookup_js_1.fullAccountKeyStringsFromShredTx; } });
@@ -26,9 +26,11 @@ export type ShredWasmTx = {
26
26
  recentBlockhash?: Uint8Array;
27
27
  addressTableLookups?: ShredAddressTableLookup[];
28
28
  };
29
- /**
30
- * 使用已解析的完整账户表(静态+ALT)解析外层指令。
31
- */
32
- export declare function dexEventsFromShredWasmTxWithFullKeys(tx: ShredWasmTx, fullAccountKeys: string[], slot: number | bigint | string, txIndex: number | bigint | string, grpcRecvUs: number | bigint | string, eventTypeFilter?: EventTypeFilter): DexEvent[];
33
- /** 仅静态账户表(无 RPC 时;V0+ALT 缺失账户以默认 pubkey 占位) */
29
+ /** 仅静态账户表(无 RPC;跳过未解析账户的指令) */
34
30
  export declare function dexEventsFromShredWasmTx(tx: ShredWasmTx, slot: number | bigint | string, txIndex: number | bigint | string, grpcRecvUs: number | bigint | string, eventTypeFilter?: EventTypeFilter): DexEvent[];
31
+ /** Full-key entry point rejects inconsistent ALT counts and indices before emitting anything. */
32
+ export declare function dexEventsFromShredWasmTxWithFullKeys(tx: ShredWasmTx, keys: string[], slot: number | bigint | string, txIndex: number | bigint | string, recvUs: number | bigint | string, filter?: EventTypeFilter): DexEvent[];
33
+ /** Explicit legacy placeholder/discriminator fallback; route adapters always require resolved keys. */
34
+ export declare function dexEventsFromShredWasmTxBestEffort(tx: ShredWasmTx, slot: number | bigint | string, txIndex: number | bigint | string, recvUs: number | bigint | string, filter?: EventTypeFilter): DexEvent[];
35
+ /** Separate writable/readonly validation avoids ambiguous counts between the two classes. */
36
+ export declare function dexEventsFromShredWasmTxWithLoadedAddresses(tx: ShredWasmTx, writable: readonly string[], readonly: readonly string[], slot: number | bigint | string, txIndex: number | bigint | string, recvUs: number | bigint | string, filter?: EventTypeFilter): DexEvent[];
@@ -1,7 +1,15 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.dexEventsFromShredWasmTxWithFullKeys = dexEventsFromShredWasmTxWithFullKeys;
4
6
  exports.dexEventsFromShredWasmTx = dexEventsFromShredWasmTx;
7
+ exports.dexEventsFromShredWasmTxWithFullKeys = dexEventsFromShredWasmTxWithFullKeys;
8
+ exports.dexEventsFromShredWasmTxBestEffort = dexEventsFromShredWasmTxBestEffort;
9
+ exports.dexEventsFromShredWasmTxWithLoadedAddresses = dexEventsFromShredWasmTxWithLoadedAddresses;
10
+ const bs58_1 = __importDefault(require("bs58"));
11
+ const metadata_js_1 = require("../core/metadata.js");
12
+ const pump_routes_js_1 = require("../instr/pump_routes.js");
5
13
  const dex_event_js_1 = require("../core/dex_event.js");
6
14
  const pumpfun_fee_enrich_js_1 = require("../core/pumpfun_fee_enrich.js");
7
15
  const types_js_1 = require("../grpc/types.js");
@@ -42,19 +50,32 @@ function ixAccountStrings(fullAccountKeys, accBytes) {
42
50
  /**
43
51
  * 使用已解析的完整账户表(静态+ALT)解析外层指令。
44
52
  */
45
- function dexEventsFromShredWasmTxWithFullKeys(tx, fullAccountKeys, slot, txIndex, grpcRecvUs, eventTypeFilter) {
53
+ function parseShredKeys(tx, fullAccountKeys, slot, txIndex, grpcRecvUs, eventTypeFilter, bestEffort = false) {
46
54
  const ixs = tx.instructions;
47
55
  if (!ixs?.length || fullAccountKeys.length === 0)
48
56
  return [];
49
57
  if (!shouldParseShredInstructions(eventTypeFilter))
50
58
  return [];
51
59
  const out = [];
52
- for (const rawIx of ixs) {
60
+ for (const [instructionIndex, rawIx] of ixs.entries()) {
53
61
  const pidIdx = rawIx.programIdIndex;
54
- if (!Number.isFinite(pidIdx) || pidIdx < 0)
62
+ if (!Number.isInteger(pidIdx) || pidIdx < 0)
55
63
  continue;
56
64
  const accBytes = asU8(rawIx.accounts);
57
65
  const data = asU8(rawIx.data);
66
+ const resolved = pidIdx < fullAccountKeys.length && accBytes.every(i => i < fullAccountKeys.length);
67
+ if (!resolved && !bestEffort)
68
+ continue;
69
+ const pid = fullAccountKeys[pidIdx];
70
+ if (pid && (0, pump_routes_js_1.mayParsePumpRoute)(pid, data)) {
71
+ if (resolved && (0, pump_routes_js_1.allowsPumpRoute)(eventTypeFilter, pid)) {
72
+ const metadata = (0, metadata_js_1.makeMetadata)(tx.signature, slot, txIndex, undefined, grpcRecvUs);
73
+ const intent = (0, pump_routes_js_1.parsePumpRoute)(pid, data, Array.from(accBytes, i => fullAccountKeys[i]), metadata, instructionIndex, eventTypeFilter);
74
+ if (intent)
75
+ out.push({ PumpRouteIntent: intent });
76
+ }
77
+ continue;
78
+ }
58
79
  const accountStrs = ixAccountStrings(fullAccountKeys, accBytes);
59
80
  if (pidIdx >= fullAccountKeys.length) {
60
81
  for (const programId of UNKNOWN_PROGRAM_CANDIDATES) {
@@ -71,10 +92,37 @@ function dexEventsFromShredWasmTxWithFullKeys(tx, fullAccountKeys, slot, txIndex
71
92
  if (ev)
72
93
  out.push(ev);
73
94
  }
95
+ if (tx.recentBlockhash && out.length) {
96
+ const recentBlockhash = bs58_1.default.encode(tx.recentBlockhash);
97
+ for (const event of out) {
98
+ const metadata = (0, dex_event_js_1.metadataForDexEvent)(event);
99
+ if (metadata)
100
+ metadata.recent_blockhash = recentBlockhash;
101
+ }
102
+ }
74
103
  (0, pumpfun_fee_enrich_js_1.enrichPumpfunSameTxPostMerge)(out);
75
104
  return out;
76
105
  }
77
- /** 仅静态账户表(无 RPC 时;V0+ALT 缺失账户以默认 pubkey 占位) */
106
+ /** 仅静态账户表(无 RPC;跳过未解析账户的指令) */
78
107
  function dexEventsFromShredWasmTx(tx, slot, txIndex, grpcRecvUs, eventTypeFilter) {
79
- return dexEventsFromShredWasmTxWithFullKeys(tx, tx.accounts, slot, txIndex, grpcRecvUs, eventTypeFilter);
108
+ return parseShredKeys(tx, tx.accounts, slot, txIndex, grpcRecvUs, eventTypeFilter);
109
+ }
110
+ /** Full-key entry point rejects inconsistent ALT counts and indices before emitting anything. */
111
+ function dexEventsFromShredWasmTxWithFullKeys(tx, keys, slot, txIndex, recvUs, filter) {
112
+ const loaded = (tx.addressTableLookups ?? []).reduce((n, l) => n + l.writableIndexes.length + l.readonlyIndexes.length, 0);
113
+ if (keys.length !== tx.accounts.length + loaded || tx.accounts.some((k, i) => keys[i] !== k)
114
+ || tx.instructions?.some(ix => !Number.isInteger(ix.programIdIndex) || ix.programIdIndex < 0 || ix.programIdIndex >= keys.length || ix.accounts.some(i => i >= keys.length)))
115
+ throw new RangeError('Inconsistent ALT keys or instruction index');
116
+ return parseShredKeys(tx, keys, slot, txIndex, recvUs, filter);
117
+ }
118
+ /** Explicit legacy placeholder/discriminator fallback; route adapters always require resolved keys. */
119
+ function dexEventsFromShredWasmTxBestEffort(tx, slot, txIndex, recvUs, filter) {
120
+ return parseShredKeys(tx, tx.accounts, slot, txIndex, recvUs, filter, true);
121
+ }
122
+ /** Separate writable/readonly validation avoids ambiguous counts between the two classes. */
123
+ function dexEventsFromShredWasmTxWithLoadedAddresses(tx, writable, readonly, slot, txIndex, recvUs, filter) {
124
+ const lookups = tx.addressTableLookups ?? [];
125
+ if (writable.length !== lookups.reduce((n, l) => n + l.writableIndexes.length, 0) || readonly.length !== lookups.reduce((n, l) => n + l.readonlyIndexes.length, 0))
126
+ throw new RangeError('ALT address counts do not match transaction');
127
+ return dexEventsFromShredWasmTxWithFullKeys(tx, [...tx.accounts, ...writable, ...readonly], slot, txIndex, recvUs, filter);
80
128
  }
@@ -1,21 +1,17 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.wireBytesToShredWasmTx = wireBytesToShredWasmTx;
7
4
  /** Native wire decoding shared with RPC routes, including V1 without ALT. */
8
- const bs58_1 = __importDefault(require("bs58"));
9
5
  const wire_transaction_js_1 = require("../wire_transaction.js");
10
6
  function wireBytesToShredWasmTx(raw) {
11
7
  try {
12
- const { transaction: tx } = (0, wire_transaction_js_1.decodeWireTransaction)(raw), msg = tx.message;
8
+ const { transaction: tx } = (0, wire_transaction_js_1.decodeWireTransactionBytes)(raw), msg = tx.message;
13
9
  if (!tx.signatures[0])
14
10
  return null;
15
11
  return { signature: tx.signatures[0], accounts: msg.accountKeys,
16
- instructions: msg.instructions.map(ix => ({ programIdIndex: ix.programIdIndex, accounts: Uint8Array.from(ix.accounts), data: bs58_1.default.decode(ix.data) })),
12
+ instructions: msg.instructions.map(ix => ({ programIdIndex: ix.programIdIndex, accounts: Uint8Array.from(ix.accounts), data: ix.data })),
17
13
  messageVersion: tx.version === 'legacy' ? 'legacy' : tx.version === 0 ? 'v0' : 'v1', header: msg.header,
18
- recentBlockhash: bs58_1.default.decode(msg.recentBlockhash),
14
+ recentBlockhash: msg.recentBlockhash,
19
15
  addressTableLookups: msg.addressTableLookups.map(l => ({ ...l, writableIndexes: Uint8Array.from(l.writableIndexes), readonlyIndexes: Uint8Array.from(l.readonlyIndexes) })) };
20
16
  }
21
17
  catch {
@@ -29,7 +29,24 @@ export interface DecodedWireTransaction {
29
29
  message: WireMessage;
30
30
  version: "legacy" | 0 | 1;
31
31
  }
32
+ type DecodedInstruction<T> = Omit<WireInstruction, "data"> & {
33
+ data: T;
34
+ };
35
+ type DecodedMessage<T> = Omit<WireMessage, "recentBlockhash" | "instructions"> & {
36
+ recentBlockhash: T;
37
+ instructions: DecodedInstruction<T>[];
38
+ };
39
+ type DecodedTransaction<T> = Omit<DecodedWireTransaction, "message"> & {
40
+ message: DecodedMessage<T>;
41
+ };
42
+ /** Public string representation retained for RPC/log consumers. */
32
43
  export declare function decodeWireTransaction(data: Uint8Array, offset?: number, requireComplete?: boolean): {
33
44
  transaction: DecodedWireTransaction;
34
45
  length: number;
35
46
  };
47
+ /** Internal Shred adapter path avoids Base58 round trips; returned payload bytes are owned copies. */
48
+ export declare function decodeWireTransactionBytes(data: Uint8Array, offset?: number, requireComplete?: boolean): {
49
+ transaction: DecodedTransaction<Uint8Array>;
50
+ length: number;
51
+ };
52
+ export {};
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.decodeWireTransaction = decodeWireTransaction;
7
+ exports.decodeWireTransactionBytes = decodeWireTransactionBytes;
7
8
  /** Native canonical Solana Legacy, V0 and V1 decoder; no Rust runtime. */
8
9
  const bs58_1 = __importDefault(require("bs58"));
9
10
  class Reader {
@@ -16,7 +17,8 @@ class Reader {
16
17
  take(n) {
17
18
  if (!Number.isSafeInteger(n) || n < 0 || this.pos + n > this.data.length)
18
19
  throw new Error("Truncated transaction");
19
- const value = this.data.slice(this.pos, this.pos + n);
20
+ // Views stay internal; public text output encodes synchronously and binary output copies.
21
+ const value = this.data.subarray(this.pos, this.pos + n);
20
22
  this.pos += n;
21
23
  return value;
22
24
  }
@@ -50,7 +52,7 @@ class Reader {
50
52
  throw new Error("Invalid short-u16");
51
53
  }
52
54
  }
53
- function decodeWireTransaction(data, offset = 0, requireComplete = true) {
55
+ function decodeWireTransactionInternal(encode, data, offset = 0, requireComplete = true) {
54
56
  if (!Number.isInteger(offset) || offset < 0 || offset >= data.length)
55
57
  throw new Error("Invalid wire offset");
56
58
  const r = new Reader(data, offset);
@@ -92,7 +94,7 @@ function decodeWireTransaction(data, offset = 0, requireComplete = true) {
92
94
  instructions = headers.map(([programIdIndex, n, length]) => ({
93
95
  programIdIndex,
94
96
  accounts: Array.from(r.take(n)),
95
- data: bs58_1.default.encode(r.take(length)),
97
+ data: encode(r.take(length)),
96
98
  }));
97
99
  signatures = Array.from({ length: header[0] }, () => r.take(64));
98
100
  if (r.pos - offset > 4096)
@@ -125,7 +127,7 @@ function decodeWireTransaction(data, offset = 0, requireComplete = true) {
125
127
  instructions.push({
126
128
  programIdIndex,
127
129
  accounts,
128
- data: bs58_1.default.encode(payload),
130
+ data: encode(payload),
129
131
  });
130
132
  }
131
133
  if (version === 0) {
@@ -148,8 +150,9 @@ function decodeWireTransaction(data, offset = 0, requireComplete = true) {
148
150
  header[1] >= header[0] ||
149
151
  header[2] > keys.length - header[0])
150
152
  throw new Error("Invalid message header");
153
+ const accountKeys = keys.map((k) => bs58_1.default.encode(k));
151
154
  if (version === 1) {
152
- if (new Set(keys.map((k) => bs58_1.default.encode(k))).size !== keys.length)
155
+ if (new Set(accountKeys).size !== keys.length)
153
156
  throw new Error("Duplicate V1 accounts");
154
157
  }
155
158
  let accountCount = keys.length;
@@ -162,7 +165,9 @@ function decodeWireTransaction(data, offset = 0, requireComplete = true) {
162
165
  if (accountCount > 256)
163
166
  throw new Error("Too many resolved account keys");
164
167
  for (const ix of instructions)
165
- if (ix.programIdIndex === 0 || ix.programIdIndex >= keys.length || ix.accounts.some(i => i >= accountCount))
168
+ if (ix.programIdIndex === 0 ||
169
+ ix.programIdIndex >= keys.length ||
170
+ ix.accounts.some((i) => i >= accountCount))
166
171
  throw new Error("Invalid instruction index");
167
172
  if (requireComplete && r.pos !== data.length)
168
173
  throw new Error("Trailing transaction bytes");
@@ -172,13 +177,12 @@ function decodeWireTransaction(data, offset = 0, requireComplete = true) {
172
177
  numReadonlySignedAccounts: header[1],
173
178
  numReadonlyUnsignedAccounts: header[2],
174
179
  },
175
- accountKeys: keys.map((k) => bs58_1.default.encode(k)),
176
- recentBlockhash: bs58_1.default.encode(hash),
180
+ accountKeys,
181
+ recentBlockhash: encode(hash),
177
182
  instructions,
178
183
  addressTableLookups: lookups,
184
+ ...(config ? { config } : {}),
179
185
  };
180
- if (config)
181
- message.config = config;
182
186
  return {
183
187
  transaction: {
184
188
  signatures: signatures.map((s) => bs58_1.default.encode(s)),
@@ -188,3 +192,11 @@ function decodeWireTransaction(data, offset = 0, requireComplete = true) {
188
192
  length: r.pos - offset,
189
193
  };
190
194
  }
195
+ /** Public string representation retained for RPC/log consumers. */
196
+ function decodeWireTransaction(data, offset = 0, requireComplete = true) {
197
+ return decodeWireTransactionInternal(bs58_1.default.encode, data, offset, requireComplete);
198
+ }
199
+ /** Internal Shred adapter path avoids Base58 round trips; returned payload bytes are owned copies. */
200
+ function decodeWireTransactionBytes(data, offset = 0, requireComplete = true) {
201
+ return decodeWireTransactionInternal((bytes) => Uint8Array.from(bytes), data, offset, requireComplete);
202
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sol-parser-sdk",
3
- "version": "0.5.18",
3
+ "version": "0.5.20",
4
4
  "description": "High-performance Solana DEX event parser for Node.js/TypeScript (Yellowstone gRPC, log parsing)",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -38,7 +38,10 @@
38
38
  "example:shredstream:subscribe": "tsx examples/shredstream_example.ts",
39
39
  "example:shredstream:pumpfun-json": "tsx examples/shredstream_pumpfun_json.ts",
40
40
  "example:shredstream": "tsx examples/shredstream_example.ts",
41
- "example:shredstream:pumpfun": "tsx examples/shredstream_pumpfun_json.ts"
41
+ "example:shredstream:pumpfun": "tsx examples/shredstream_pumpfun_json.ts",
42
+ "example:pump:replay": "tsx examples/pump_shred_routes.ts",
43
+ "example:pump:bank": "tsx examples/pump_offline_bank.ts",
44
+ "check:pump-examples": "tsc --noEmit --target ES2022 --module NodeNext --moduleResolution NodeNext --strict --esModuleInterop --skipLibCheck examples/pump_shred_routes.ts examples/pump_offline_bank.ts examples/hotpath_benchmark.ts"
42
45
  },
43
46
  "keywords": [
44
47
  "solana",
@@ -49,8 +52,10 @@
49
52
  ],
50
53
  "license": "MIT",
51
54
  "devDependencies": {
55
+ "@solana/kit": "8.5.0",
52
56
  "@types/node": "^22.19.17",
53
57
  "dotenv": "^17.4.1",
58
+ "litesvm": "1.6.0",
54
59
  "tsx": "^4.21.0",
55
60
  "typescript": "^5.6.3",
56
61
  "vitest": "^2.1.9"