sol-parser-sdk 0.5.17 → 0.5.18

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.
Files changed (64) hide show
  1. package/README.md +24 -15
  2. package/README_CN.md +23 -14
  3. package/dist/accounts/pumpfun.js +15 -0
  4. package/dist/accounts/pumpswap.js +2 -0
  5. package/dist/core/account_dispatcher_rpc.d.ts +2 -1
  6. package/dist/core/account_dispatcher_rpc.js +94 -9
  7. package/dist/core/account_fill_pumpfun.js +20 -0
  8. package/dist/core/account_fill_pumpswap.d.ts +2 -0
  9. package/dist/core/account_fill_pumpswap.js +55 -6
  10. package/dist/core/account_fill_raydium.js +4 -0
  11. package/dist/core/dex_event.d.ts +149 -0
  12. package/dist/grpc/client.js +2 -0
  13. package/dist/grpc/log_instr_dedup.js +75 -7
  14. package/dist/grpc/order_buffer.d.ts +5 -0
  15. package/dist/grpc/order_buffer.js +53 -17
  16. package/dist/grpc/types.d.ts +4 -1
  17. package/dist/grpc/types.js +23 -0
  18. package/dist/index.d.ts +1 -0
  19. package/dist/index.js +1 -0
  20. package/dist/instr/inner.js +28 -1
  21. package/dist/instr/meteora_damm_ix.js +26 -0
  22. package/dist/instr/meteora_pools_ix.js +17 -9
  23. package/dist/instr/orca_whirlpool_ix.js +13 -9
  24. package/dist/instr/pumpfun_ix.js +84 -0
  25. package/dist/instr/pumpswap_ix.js +85 -10
  26. package/dist/instr/raydium_clmm_ix.js +5 -3
  27. package/dist/instr/raydium_cpmm_ix.js +11 -8
  28. package/dist/logs/meteora_damm.d.ts +7 -0
  29. package/dist/logs/meteora_damm.js +211 -0
  30. package/dist/logs/meteora_dbc.d.ts +3 -0
  31. package/dist/logs/meteora_dbc.js +23 -0
  32. package/dist/logs/meteora_dlmm.js +16 -4
  33. package/dist/logs/optimized_matcher.js +93 -10
  34. package/dist/logs/program_log_discriminators.d.ts +11 -0
  35. package/dist/logs/program_log_discriminators.js +11 -0
  36. package/dist/logs/pump.js +6 -3
  37. package/dist/logs/pump_amm.js +8 -2
  38. package/dist/logs/pump_upgrade.d.ts +68 -0
  39. package/dist/logs/pump_upgrade.js +128 -0
  40. package/dist/logs/raydium_cpmm.js +7 -3
  41. package/dist/rpc_transaction.js +84 -7
  42. package/dist/shredstream/alt_cache.d.ts +26 -0
  43. package/dist/shredstream/alt_cache.js +138 -0
  44. package/dist/shredstream/client.d.ts +11 -3
  45. package/dist/shredstream/client.js +76 -72
  46. package/dist/shredstream/config.d.ts +7 -3
  47. package/dist/shredstream/index.d.ts +3 -2
  48. package/dist/shredstream/index.js +5 -3
  49. package/dist/shredstream/instruction_parse.d.ts +1 -1
  50. package/dist/shredstream/instruction_parse.js +1 -0
  51. package/dist/simulation_route.d.ts +1 -1
  52. package/dist/simulation_route.js +17 -4
  53. package/dist/transaction_route.js +20 -1
  54. package/dist/wire_transaction.js +9 -10
  55. package/docs/USAGE.md +161 -0
  56. package/package.json +2 -5
  57. package/NATIVE_ALIGNMENT.md +0 -312
  58. package/NATIVE_DAMM_FACTORY_ALIGNMENT_20261004.md +0 -16
  59. package/NATIVE_DAMM_FACTORY_EVIDENCE_20261004.json +0 -55
  60. package/NATIVE_MIGRATION.md +0 -38
  61. package/NATIVE_PUMPFUN_NATIVE_DEBIT_ALIGNMENT_20261004.md +0 -18
  62. package/NATIVE_PUMPFUN_NATIVE_DEBIT_EVIDENCE_20261004.json +0 -57
  63. package/NATIVE_PUMPFUN_SETTLEMENT_ALIGNMENT_20261004.md +0 -11
  64. package/NATIVE_PUMPFUN_SETTLEMENT_EVIDENCE_20261004.json +0 -70
package/README.md CHANGED
@@ -18,17 +18,27 @@
18
18
 
19
19
  ---
20
20
 
21
- ## Other language SDKs
21
+ ## 📦 SDK Versions and Related SDKs
22
22
 
23
- | Language | Repository |
24
- |----------|------------|
25
- | Rust | [sol-parser-sdk](https://github.com/0xfnzero/sol-parser-sdk) |
26
- | Node.js | [sol-parser-sdk-nodejs](https://github.com/0xfnzero/sol-parser-sdk-nodejs) |
27
- | Python | [sol-parser-sdk-python](https://github.com/0xfnzero/sol-parser-sdk-python) |
28
- | Go | [sol-parser-sdk-golang](https://github.com/0xfnzero/sol-parser-sdk-golang) |
23
+ Parser SDK language versions and related Rust SDKs:
24
+
25
+ | Language | Repository | Description | Version |
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` |
29
33
 
30
34
  ---
31
35
 
36
+ ## v0.5.18 — Signed transaction and hot-path hardening
37
+
38
+ 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.
39
+
40
+ Validation includes local CPU benchmarks and offline signed-bank scenarios. Measured hot paths use cached inputs without RPC. Benchmarks do not establish production network or transaction-landing latency. No funded mainnet transactions were broadcast.
41
+
32
42
  ## What This SDK Is For
33
43
 
34
44
  `sol-parser-sdk` is the TypeScript/Node.js implementation of the FnZero Solana DEX parser SDK. The GitHub repository is named `sol-parser-sdk-nodejs` to distinguish it from the Rust/Python/Go repositories. It is built for bots, indexers, copy-trading services, sniper pipelines, and backend systems that need typed DEX events from Yellowstone gRPC, Jito ShredStream, RPC transactions, or protocol account data.
@@ -103,7 +113,7 @@
103
113
  **From npm**
104
114
 
105
115
  ```bash
106
- npm install sol-parser-sdk@0.5.17
116
+ npm install sol-parser-sdk@0.5.18
107
117
  ```
108
118
 
109
119
  **From source** (folder may be named `sol-parser-sdk-ts` in a monorepo)
@@ -270,7 +280,7 @@ The client decodes gRPC `entries` bytes in **TypeScript** (same layout as the Go
270
280
  npx tsx examples/shredstream_example.ts -- --url=http://127.0.0.1:10800
271
281
  ```
272
282
 
273
- Without RPC, V0 ALT-loaded account indexes are represented with default pubkey placeholders and parsed best-effort. `shredstream_pumpfun_json.ts` can also use Solana **`RPC_URL`** (or `--rpc`) to expand ALTs when exact loaded-account fields are required.
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.
274
284
 
275
285
  ---
276
286
 
@@ -298,7 +308,7 @@ From the **package root** after `npm install`. Examples use `npx tsx` and load `
298
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) |
299
309
  | **ShredStream** (HTTP, not Yellowstone gRPC; see **step 5** above) | | |
300
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) |
301
- | PumpFun `DexEvent` JSON from ShredStream; static ALT fallback works without RPC, and Solana **RPC** (`RPC_URL` or `--rpc`) expands full ALT accounts when needed. | `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) |
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) |
302
312
  | **Multi-protocol** | | |
303
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) |
304
314
  | **Utility** | | |
@@ -342,12 +352,11 @@ npm run check:migration # parity checks; needs build
342
352
 
343
353
  MIT — https://github.com/0xfnzero/sol-parser-sdk-nodejs
344
354
 
345
- ## Native alignment status
346
-
347
- See [NATIVE_ALIGNMENT.md](NATIVE_ALIGNMENT.md) for implemented native APIs, Rust golden tests, mainnet simulation evidence, examples, and remaining parity gaps. Full cross-language parity is still in progress.
355
+ ## API compatibility
348
356
 
357
+ Full cross-language API parity is still in progress. See the [API migration guide](docs/USAGE.md#api-compatibility) for public behavior and support boundaries, and the examples directory for usage.
349
358
 
350
- 实时 parser → trade 接入使用 Yellowstone **gRPC**;见 [gRPC 缓存接入与三语言示例](examples/GRPC_CACHE.md)。此路径不使用 WebSocket,报价和构建热路径不调用 RPC。
351
359
 
360
+ 实时 parser → trade 接入使用 Yellowstone **gRPC**;见 [gRPC 缓存接入与三语言示例](docs/USAGE.md#grpc-cache)。此路径不使用 WebSocket,报价和构建热路径不调用 RPC。
352
361
 
353
- [本轮原生对齐 API 迁移](NATIVE_MIGRATION.md)(实施中,尚未发布)。
362
+ 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).
package/README_CN.md CHANGED
@@ -18,14 +18,18 @@
18
18
 
19
19
  ---
20
20
 
21
- ## 其他语言 SDK
21
+ ## 📦 SDK 版本与相关项目
22
22
 
23
- | 语言 | 仓库 |
24
- |------|------|
25
- | Rust | [sol-parser-sdk](https://github.com/0xfnzero/sol-parser-sdk) |
26
- | Node.js | [sol-parser-sdk-nodejs](https://github.com/0xfnzero/sol-parser-sdk-nodejs) |
27
- | Python | [sol-parser-sdk-python](https://github.com/0xfnzero/sol-parser-sdk-python) |
28
- | Go | [sol-parser-sdk-golang](https://github.com/0xfnzero/sol-parser-sdk-golang) |
23
+ 解析 SDK 的各语言版本及相关 Rust SDK:
24
+
25
+ | 语言 | 仓库 | 描述 | 版本 |
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` |
29
33
 
30
34
  ---
31
35
 
@@ -44,6 +48,12 @@
44
48
 
45
49
  ## 发布说明
46
50
 
51
+ ## v0.5.18 — Signed transaction and hot-path hardening
52
+
53
+ 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.
54
+
55
+ Validation includes local CPU benchmarks and offline signed-bank scenarios. Measured hot paths use cached inputs without RPC. Benchmarks do not establish production network or transaction-landing latency. No funded mainnet transactions were broadcast.
56
+
47
57
  ### v0.5.17
48
58
 
49
59
  - 按实际指令 discriminator 和事件 mint 匹配 PumpFun create/create_v2 账户,支持 CPI,并拒绝猜测有歧义的匹配。
@@ -103,7 +113,7 @@
103
113
  **npm**
104
114
 
105
115
  ```bash
106
- npm install sol-parser-sdk@0.5.17
116
+ npm install sol-parser-sdk@0.5.18
107
117
  ```
108
118
 
109
119
  **源码**(monorepo 里目录可能是 `sol-parser-sdk-ts`)
@@ -263,7 +273,7 @@ mint 或 quote mint 映射到 pool,再将 `PumpSwapLiquidityAdded.user` 与该
263
273
  npx tsx examples/shredstream_example.ts -- --url=http://127.0.0.1:10800
264
274
  ```
265
275
 
266
- 无 RPC 时,V0 ALT-loaded 账户索引用默认 pubkey 占位并继续 best-effort 解析。若需要精确的 ALT 加载账户字段,`shredstream_pumpfun_json.ts` 也可以使用 Solana **`RPC_URL`**(或 `--rpc`)展开 ALT。
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。
267
277
 
268
278
  ---
269
279
 
@@ -291,7 +301,7 @@ npx tsx examples/shredstream_example.ts -- --url=http://127.0.0.1:10800
291
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) |
292
302
  | **ShredStream**(HTTP,**非** Yellowstone gRPC;端点见上文步骤 5) | | |
293
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) |
294
- | ShredStream → PumpFun `DexEvent` JSON;无 RPC 时可静态 ALT fallback,配置 Solana **RPC**(`RPC_URL` 或 `--rpc`)时可展开完整 ALT 账户。 | `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) |
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) |
295
305
  | **多协议** | | |
296
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) |
297
307
  | **工具** | | |
@@ -335,9 +345,8 @@ npm run check:migration # 对齐与校验,需先 build
335
345
 
336
346
  MIT — https://github.com/0xfnzero/sol-parser-sdk-nodejs
337
347
 
338
- ## Native alignment status
339
-
340
- See [NATIVE_ALIGNMENT.md](NATIVE_ALIGNMENT.md) for implemented native APIs, Rust golden tests, mainnet simulation evidence, examples, and remaining parity gaps. Full cross-language parity is still in progress.
348
+ ## API 兼容性
341
349
 
350
+ 完整跨语言 API 对齐仍在进行;公开行为和支持边界见 [API 迁移说明](docs/USAGE.md#api-compatibility),使用方法见 examples 目录。
342
351
 
343
- [本轮原生对齐 API 迁移](NATIVE_MIGRATION.md)(实施中,尚未发布)。
352
+ PumpFun create/create_v2 的共享主网样本、重放方法和验证边界见 [验证说明](https://github.com/0xfnzero/sol-parser-sdk-golang/tree/main/validation/pumpfun_create_20261007)。
@@ -220,6 +220,11 @@ function parsePumpfunGlobal(account, metadata) {
220
220
  return null;
221
221
  const whitelisted_quote_mints = whitelistedQuoteMints.value;
222
222
  const global = {
223
+ creator_fee_configurable: d[1037] === 1,
224
+ max_configurable_creator_fee_bps: (0, binary_js_1.readU64LE)(d, 1038) ?? 0n,
225
+ holder_reward_claim_authority: (0, binary_js_1.readPubkey)(d, 1046) ?? "11111111111111111111111111111111",
226
+ is_holder_reward_enabled: d[1078] === 1,
227
+ max_curve_depth: d[1079] ?? 0,
223
228
  initialized,
224
229
  authority,
225
230
  fee_recipient,
@@ -311,6 +316,12 @@ function parsePumpfunBondingCurve(account, metadata) {
311
316
  o += 1;
312
317
  const is_holder_reward = ((0, binary_js_1.readU8)(d, o) ?? 0) !== 0;
313
318
  const bonding_curve = {
319
+ creator_fee: (0, binary_js_1.readU64LE)(d, 117) ?? 0n,
320
+ protocol_fees: (0, binary_js_1.readU64LE)(d, 125) ?? 0n,
321
+ depth: (0, binary_js_1.readU8)(d, 133) ?? 0,
322
+ initial_virtual_quote_reserves: (0, binary_js_1.readU64LE)(d, 134) ?? 0n,
323
+ post_complete_base_out: (0, binary_js_1.readU64LE)(d, 142) ?? 0n,
324
+ post_complete_quote_in: (0, binary_js_1.readU64LE)(d, 150) ?? 0n,
314
325
  virtual_token_reserves,
315
326
  virtual_quote_reserves,
316
327
  real_token_reserves,
@@ -356,7 +367,11 @@ function parsePumpfunFeeConfig(account, metadata) {
356
367
  const stableFeeTiers = readFeeTiers(d, o);
357
368
  if (stableFeeTiers === null)
358
369
  return null;
370
+ const exotic = stableFeeTiers.next === d.length ? { value: { lp_fee_bps: 0n, protocol_fee_bps: 0n, creator_fee_bps: 0n } } : readFees(d, stableFeeTiers.next);
371
+ if (exotic === null)
372
+ return null;
359
373
  const fee_config = {
374
+ exotic_flat_fees: exotic.value,
360
375
  bump,
361
376
  admin,
362
377
  flat_fees: flatFees.value,
@@ -181,6 +181,8 @@ function parsePumpswapPool(account, metadata) {
181
181
  o += 1;
182
182
  const is_holder_reward = ((0, binary_js_1.readU8)(d, o) ?? 0) !== 0;
183
183
  const pool = {
184
+ protocol_fees: (0, binary_js_1.readU64LE)(d, 263) ?? 0n,
185
+ creator_fees: (0, binary_js_1.readU64LE)(d, 271) ?? 0n,
184
186
  pool_bump,
185
187
  index,
186
188
  creator,
@@ -1,9 +1,10 @@
1
+ import { PublicKey } from "@solana/web3.js";
1
2
  /**
2
3
  * RPC 路径账户填充(`fillAccountsFromTransactionDataRpc`)。
3
4
  * `RaydiumClmmOpenPositionWithTokenExtNft` 与 `openPosition` 共用账户索引(见 `account_fill_raydium.ts`)。
4
5
  */
5
6
  import type { DexEvent } from "./dex_event.js";
6
- import type { ConfirmedTransactionMeta, Message, MessageV0, PublicKey } from "@solana/web3.js";
7
+ import type { ConfirmedTransactionMeta, Message, MessageV0 } from "@solana/web3.js";
7
8
  import { type InvokePair } from "./rpc_invoke_map.js";
8
9
  /** 就地修改事件体内字段 */
9
10
  export declare function fillAccountsFromTransactionDataRpc(ev: DexEvent, message: Message | MessageV0, meta: ConfirmedTransactionMeta | null, programInvokes: Map<string, InvokePair[]>, resolver: {
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.fillAccountsFromTransactionDataRpc = fillAccountsFromTransactionDataRpc;
4
+ const web3_js_1 = require("@solana/web3.js");
4
5
  const program_ids_js_1 = require("../instr/program_ids.js");
5
6
  const rpc_invoke_map_js_1 = require("./rpc_invoke_map.js");
6
7
  const account_fill_pumpfun_js_1 = require("./account_fill_pumpfun.js");
@@ -9,13 +10,18 @@ const account_fill_raydium_js_1 = require("./account_fill_raydium.js");
9
10
  const account_fill_orca_js_1 = require("./account_fill_orca.js");
10
11
  const account_fill_raydium_launchlab_js_1 = require("./account_fill_raydium_launchlab.js");
11
12
  const account_fill_meteora_js_1 = require("./account_fill_meteora.js");
12
- function tryFill(programId, programInvokes, message, meta, resolver, fn, anchor, unambiguous = false) {
13
+ function tryFill(programId, programInvokes, message, meta, resolver, fn, anchor, unambiguous = false, allowedDiscriminators) {
13
14
  if (anchor || unambiguous) {
14
15
  const hasAnchor = anchor && anchor.pool && anchor.pool !== "11111111111111111111111111111111";
15
16
  if (!hasAnchor && !unambiguous)
16
17
  return;
17
18
  let selected = null;
18
19
  for (const invocation of programInvokes.get(programId) ?? []) {
20
+ if (allowedDiscriminators) {
21
+ const raw = (0, rpc_invoke_map_js_1.getInstructionDataBytes)(message, meta, invocation);
22
+ if (!raw || !allowedDiscriminators.some(disc => disc.every((v, i) => raw[i] === v)))
23
+ continue;
24
+ }
19
25
  const candidate = (0, rpc_invoke_map_js_1.makeInvokeAccountGetter)(resolver, invocation, message, meta);
20
26
  if (!candidate || (hasAnchor && candidate(anchor.index) !== anchor.pool))
21
27
  continue;
@@ -40,6 +46,79 @@ function tryFill(programId, programInvokes, message, meta, resolver, fn, anchor,
40
46
  }
41
47
  /** 就地修改事件体内字段 */
42
48
  function fillAccountsFromTransactionDataRpc(ev, message, meta, programInvokes, resolver) {
49
+ const fillPumpTrade = (e) => {
50
+ if (!e.mint || e.mint === "11111111111111111111111111111111")
51
+ return;
52
+ // Discriminator -> mint index, user index, direction, required IDL accounts.
53
+ const layouts = {
54
+ "102,6,61,18,1,218,235,234": [2, 6, true, 16],
55
+ "56,252,116,8,158,223,205,95": [2, 6, true, 16],
56
+ "51,230,133,164,1,127,131,173": [2, 6, false, 14],
57
+ "184,23,238,97,103,197,211,61": [1, 13, true, 27],
58
+ "194,171,28,70,104,77,91,47": [1, 13, true, 27],
59
+ "93,246,130,60,231,233,64,178": [1, 13, false, 26],
60
+ "7,5,29,196,245,23,101,80": [1, 8, true, 17],
61
+ "225,247,80,30,213,179,132,136": [1, 8, true, 17],
62
+ "28,146,222,119,38,196,105,213": [1, 8, false, 17],
63
+ };
64
+ let selected;
65
+ for (const invoke of programInvokes.get(program_ids_js_1.PUMPFUN_PROGRAM_ID) ?? []) {
66
+ const raw = (0, rpc_invoke_map_js_1.getInstructionDataBytes)(message, meta, invoke);
67
+ const layout = raw && layouts[raw.slice(0, 8).join(",")];
68
+ if (!layout)
69
+ continue;
70
+ const [mintIndex, userIndex, buy, minimum] = layout;
71
+ if (buy !== e.is_buy || (0, rpc_invoke_map_js_1.countInstructionAccounts)(message, meta, invoke) < minimum)
72
+ continue;
73
+ const get = (0, rpc_invoke_map_js_1.makeInvokeAccountGetter)(resolver, invoke, message, meta);
74
+ if (!get || get(mintIndex) !== e.mint || (e.user && e.user !== "11111111111111111111111111111111" && get(userIndex) !== e.user))
75
+ continue;
76
+ if (selected)
77
+ return;
78
+ selected = get;
79
+ }
80
+ if (selected)
81
+ (0, account_fill_pumpfun_js_1.fillPumpfunTradeAccounts)(e, selected);
82
+ };
83
+ const fillSwap = (e, buy) => {
84
+ if (!e.pool || e.pool === "11111111111111111111111111111111")
85
+ return;
86
+ const legacy = buy
87
+ ? ["102,6,61,18,1,218,235,234", "198,46,21,82,180,217,232,112"]
88
+ : ["51,230,133,164,1,127,131,173"];
89
+ const compact = buy
90
+ ? ["184,23,238,97,103,197,211,61", "194,171,28,70,104,77,91,47"]
91
+ : ["93,246,130,60,231,233,64,178"];
92
+ let selected;
93
+ for (const invoke of programInvokes.get(program_ids_js_1.PUMPSWAP_PROGRAM_ID) ?? []) {
94
+ const raw = (0, rpc_invoke_map_js_1.getInstructionDataBytes)(message, meta, invoke);
95
+ const disc = raw?.slice(0, 8).join(",");
96
+ const boost = buy && disc === "105,68,6,175,0,7,35,162";
97
+ if (!disc || (!boost && !legacy.includes(disc) && !compact.includes(disc)))
98
+ continue;
99
+ const minimum = boost ? 13 : compact.includes(disc) ? 17 : buy ? 23 : 21;
100
+ if ((0, rpc_invoke_map_js_1.countInstructionAccounts)(message, meta, invoke) < minimum)
101
+ continue;
102
+ const get = (0, rpc_invoke_map_js_1.makeInvokeAccountGetter)(resolver, invoke, message, meta);
103
+ if (!get ||
104
+ get(0) !== e.pool ||
105
+ (e.user &&
106
+ e.user !== "11111111111111111111111111111111" &&
107
+ get(boost ? 7 : 1) !== e.user))
108
+ continue;
109
+ if (selected)
110
+ return;
111
+ selected = { get, boost };
112
+ }
113
+ if (selected) {
114
+ if (selected.boost)
115
+ (0, account_fill_pumpswap_js_1.fillPumpswapBoostBuyAccounts)(e, selected.get);
116
+ else if (buy)
117
+ (0, account_fill_pumpswap_js_1.fillPumpswapBuyAccounts)(e, selected.get);
118
+ else
119
+ (0, account_fill_pumpswap_js_1.fillPumpswapSellAccounts)(e, selected.get);
120
+ }
121
+ };
43
122
  const fillCreate = (e, v2Only = false) => {
44
123
  let selected;
45
124
  for (const invoke of programInvokes.get(program_ids_js_1.PUMPFUN_PROGRAM_ID) ?? []) {
@@ -65,16 +144,16 @@ function fillAccountsFromTransactionDataRpc(ev, message, meta, programInvokes, r
65
144
  }
66
145
  };
67
146
  if ("PumpFunTrade" in ev) {
68
- tryFill(program_ids_js_1.PUMPFUN_PROGRAM_ID, programInvokes, message, meta, resolver, (g) => (0, account_fill_pumpfun_js_1.fillPumpfunTradeAccounts)(ev.PumpFunTrade, g));
147
+ fillPumpTrade(ev.PumpFunTrade);
69
148
  }
70
149
  else if ("PumpFunBuy" in ev) {
71
- tryFill(program_ids_js_1.PUMPFUN_PROGRAM_ID, programInvokes, message, meta, resolver, (g) => (0, account_fill_pumpfun_js_1.fillPumpfunTradeAccounts)(ev.PumpFunBuy, g));
150
+ fillPumpTrade(ev.PumpFunBuy);
72
151
  }
73
152
  else if ("PumpFunSell" in ev) {
74
- tryFill(program_ids_js_1.PUMPFUN_PROGRAM_ID, programInvokes, message, meta, resolver, (g) => (0, account_fill_pumpfun_js_1.fillPumpfunTradeAccounts)(ev.PumpFunSell, g));
153
+ fillPumpTrade(ev.PumpFunSell);
75
154
  }
76
155
  else if ("PumpFunBuyExactSolIn" in ev) {
77
- tryFill(program_ids_js_1.PUMPFUN_PROGRAM_ID, programInvokes, message, meta, resolver, (g) => (0, account_fill_pumpfun_js_1.fillPumpfunTradeAccounts)(ev.PumpFunBuyExactSolIn, g));
156
+ fillPumpTrade(ev.PumpFunBuyExactSolIn);
78
157
  }
79
158
  else if ("PumpFunCreate" in ev) {
80
159
  fillCreate(ev.PumpFunCreate);
@@ -86,10 +165,10 @@ function fillAccountsFromTransactionDataRpc(ev, message, meta, programInvokes, r
86
165
  tryFill(program_ids_js_1.PUMPFUN_PROGRAM_ID, programInvokes, message, meta, resolver, (g) => (0, account_fill_pumpfun_js_1.fillPumpfunMigrateAccounts)(ev.PumpFunMigrate, g));
87
166
  }
88
167
  else if ("PumpSwapBuy" in ev) {
89
- tryFill(program_ids_js_1.PUMPSWAP_PROGRAM_ID, programInvokes, message, meta, resolver, (g) => (0, account_fill_pumpswap_js_1.fillPumpswapBuyAccounts)(ev.PumpSwapBuy, g));
168
+ fillSwap(ev.PumpSwapBuy, true);
90
169
  }
91
170
  else if ("PumpSwapSell" in ev) {
92
- tryFill(program_ids_js_1.PUMPSWAP_PROGRAM_ID, programInvokes, message, meta, resolver, (g) => (0, account_fill_pumpswap_js_1.fillPumpswapSellAccounts)(ev.PumpSwapSell, g));
171
+ fillSwap(ev.PumpSwapSell, false);
93
172
  }
94
173
  else if ("PumpSwapTrade" in ev) {
95
174
  tryFill(program_ids_js_1.PUMPSWAP_PROGRAM_ID, programInvokes, message, meta, resolver, (g) => (0, account_fill_pumpswap_js_1.fillPumpswapTradeAccounts)(ev.PumpSwapTrade, g));
@@ -119,10 +198,16 @@ function fillAccountsFromTransactionDataRpc(ev, message, meta, programInvokes, r
119
198
  tryFill(program_ids_js_1.RAYDIUM_CLMM_PROGRAM_ID, programInvokes, message, meta, resolver, (g) => (0, account_fill_raydium_js_1.fillRaydiumClmmClosePositionAccounts)(ev.RaydiumClmmClosePosition, g));
120
199
  }
121
200
  else if ("RaydiumClmmIncreaseLiquidity" in ev) {
122
- tryFill(program_ids_js_1.RAYDIUM_CLMM_PROGRAM_ID, programInvokes, message, meta, resolver, (g) => (0, account_fill_raydium_js_1.fillRaydiumClmmIncreaseLiquidityAccounts)(ev.RaydiumClmmIncreaseLiquidity, g));
201
+ if (ev.RaydiumClmmIncreaseLiquidity.position_nft_mint && ev.RaydiumClmmIncreaseLiquidity.position_nft_mint !== "11111111111111111111111111111111") {
202
+ ev.RaydiumClmmIncreaseLiquidity.personal_position = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("position"), new web3_js_1.PublicKey(ev.RaydiumClmmIncreaseLiquidity.position_nft_mint).toBuffer()], new web3_js_1.PublicKey(program_ids_js_1.RAYDIUM_CLMM_PROGRAM_ID))[0].toBase58();
203
+ }
204
+ tryFill(program_ids_js_1.RAYDIUM_CLMM_PROGRAM_ID, programInvokes, message, meta, resolver, (g) => (0, account_fill_raydium_js_1.fillRaydiumClmmIncreaseLiquidityAccounts)(ev.RaydiumClmmIncreaseLiquidity, g), { pool: ev.RaydiumClmmIncreaseLiquidity.personal_position ?? "", index: 4 }, false, [[133, 29, 89, 223, 69, 238, 176, 10], [46, 156, 243, 118, 13, 205, 251, 178]]);
123
205
  }
124
206
  else if ("RaydiumClmmDecreaseLiquidity" in ev) {
125
- tryFill(program_ids_js_1.RAYDIUM_CLMM_PROGRAM_ID, programInvokes, message, meta, resolver, (g) => (0, account_fill_raydium_js_1.fillRaydiumClmmDecreaseLiquidityAccounts)(ev.RaydiumClmmDecreaseLiquidity, g));
207
+ if (ev.RaydiumClmmDecreaseLiquidity.position_nft_mint && ev.RaydiumClmmDecreaseLiquidity.position_nft_mint !== "11111111111111111111111111111111") {
208
+ ev.RaydiumClmmDecreaseLiquidity.personal_position = web3_js_1.PublicKey.findProgramAddressSync([Buffer.from("position"), new web3_js_1.PublicKey(ev.RaydiumClmmDecreaseLiquidity.position_nft_mint).toBuffer()], new web3_js_1.PublicKey(program_ids_js_1.RAYDIUM_CLMM_PROGRAM_ID))[0].toBase58();
209
+ }
210
+ tryFill(program_ids_js_1.RAYDIUM_CLMM_PROGRAM_ID, programInvokes, message, meta, resolver, (g) => (0, account_fill_raydium_js_1.fillRaydiumClmmDecreaseLiquidityAccounts)(ev.RaydiumClmmDecreaseLiquidity, g), { pool: ev.RaydiumClmmDecreaseLiquidity.personal_position ?? "", index: 2 }, false, [[58, 127, 188, 62, 79, 82, 196, 96], [160, 38, 208, 111, 104, 91, 44, 1]]);
126
211
  }
127
212
  else if ("RaydiumCpmmSwap" in ev) {
128
213
  tryFill(program_ids_js_1.RAYDIUM_CPMM_PROGRAM_ID, programInvokes, message, meta, resolver, (g) => (0, account_fill_raydium_js_1.fillRaydiumCpmmSwapAccounts)(ev.RaydiumCpmmSwap, g));
@@ -15,6 +15,26 @@ function fillPumpfunTradeAccounts(e, get) {
15
15
  e[key] = get(idx);
16
16
  }
17
17
  };
18
+ if (get(16) === "6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P" && accountAtMatchesMint(1)) {
19
+ set("global", 0);
20
+ set("mint", 1);
21
+ set("quote_mint", 2);
22
+ set("token_program", 3);
23
+ set("quote_token_program", 4);
24
+ set("bonding_curve", 5);
25
+ set("associated_bonding_curve", 6);
26
+ set("associated_quote_bonding_curve", 7);
27
+ set("user", 8);
28
+ set("associated_user", 9);
29
+ set("associated_quote_user", 10);
30
+ set("user_volume_accumulator", 11);
31
+ set("fee_config", 12);
32
+ set("buyback_fee_recipient", 13);
33
+ set("system_program", 14);
34
+ set("event_authority", 15);
35
+ set("program", 16);
36
+ return;
37
+ }
18
38
  const isV2 = e.ix_name === "buy_v2" ||
19
39
  e.ix_name === "sell_v2" ||
20
40
  e.ix_name === "buy_exact_quote_in_v2" ||
@@ -1,5 +1,7 @@
1
1
  /** PumpSwap 账户填充 */
2
2
  import type { PumpSwapBuyEvent, PumpSwapCreatePoolEvent, PumpSwapLiquidityAdded, PumpSwapLiquidityRemoved, PumpSwapSellEvent, PumpSwapTradeEvent } from "./dex_event.js";
3
+ /** The boost layout has no user ATAs or fee accounts. Preserve decoded values. */
4
+ export declare function fillPumpswapBoostBuyAccounts(e: PumpSwapBuyEvent, get: (i: number) => string): void;
3
5
  export declare function fillPumpswapBuyAccounts(e: PumpSwapBuyEvent, get: (i: number) => string): void;
4
6
  export declare function fillPumpswapSellAccounts(e: PumpSwapSellEvent, get: (i: number) => string): void;
5
7
  export declare function fillPumpswapCreatePoolAccounts(e: PumpSwapCreatePoolEvent, get: (i: number) => string): void;
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fillPumpswapBoostBuyAccounts = fillPumpswapBoostBuyAccounts;
3
4
  exports.fillPumpswapBuyAccounts = fillPumpswapBuyAccounts;
4
5
  exports.fillPumpswapSellAccounts = fillPumpswapSellAccounts;
5
6
  exports.fillPumpswapCreatePoolAccounts = fillPumpswapCreatePoolAccounts;
@@ -8,6 +9,16 @@ exports.fillPumpswapLiquidityAddedAccounts = fillPumpswapLiquidityAddedAccounts;
8
9
  exports.fillPumpswapLiquidityRemovedAccounts = fillPumpswapLiquidityRemovedAccounts;
9
10
  const dex_event_js_1 = require("./dex_event.js");
10
11
  const Z = () => (0, dex_event_js_1.defaultPubkey)();
12
+ const TOKEN_PROGRAMS = new Set([
13
+ "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
14
+ "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb",
15
+ ]);
16
+ function isCompactTrade(get) {
17
+ // Index 16 is the program in both legacy and compact layouts.
18
+ return (get(16) === "pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA" &&
19
+ TOKEN_PROGRAMS.has(get(9)) &&
20
+ TOKEN_PROGRAMS.has(get(10)));
21
+ }
11
22
  function fillPumpswapTradeCommon(e, get) {
12
23
  const zero = Z();
13
24
  if (!e.pool || e.pool === zero)
@@ -30,10 +41,21 @@ function fillPumpswapTradeCommon(e, get) {
30
41
  if (!e.pool_quote_token_account || e.pool_quote_token_account === zero) {
31
42
  e.pool_quote_token_account = get(8);
32
43
  }
44
+ if (isCompactTrade(get)) {
45
+ if (!e.base_token_program || e.base_token_program === zero)
46
+ e.base_token_program = get(9);
47
+ if (!e.quote_token_program || e.quote_token_program === zero)
48
+ e.quote_token_program = get(10);
49
+ if (!e.fee_recipient_quote_token_account ||
50
+ e.fee_recipient_quote_token_account === zero)
51
+ e.fee_recipient_quote_token_account = get(14);
52
+ return;
53
+ }
33
54
  if (!e.protocol_fee_recipient || e.protocol_fee_recipient === zero) {
34
55
  e.protocol_fee_recipient = get(9);
35
56
  }
36
- if (!e.protocol_fee_recipient_token_account || e.protocol_fee_recipient_token_account === zero) {
57
+ if (!e.protocol_fee_recipient_token_account ||
58
+ e.protocol_fee_recipient_token_account === zero) {
37
59
  e.protocol_fee_recipient_token_account = get(10);
38
60
  }
39
61
  if (!e.base_token_program || e.base_token_program === zero)
@@ -42,12 +64,33 @@ function fillPumpswapTradeCommon(e, get) {
42
64
  e.quote_token_program = get(12);
43
65
  if (!e.coin_creator_vault_ata || e.coin_creator_vault_ata === zero)
44
66
  e.coin_creator_vault_ata = get(17);
45
- if (!e.coin_creator_vault_authority || e.coin_creator_vault_authority === zero) {
67
+ if (!e.coin_creator_vault_authority ||
68
+ e.coin_creator_vault_authority === zero) {
46
69
  e.coin_creator_vault_authority = get(18);
47
70
  }
48
71
  }
72
+ /** The boost layout has no user ATAs or fee accounts. Preserve decoded values. */
73
+ function fillPumpswapBoostBuyAccounts(e, get) {
74
+ const zero = Z();
75
+ const roles = {
76
+ pool: 0,
77
+ base_mint: 3,
78
+ quote_mint: 4,
79
+ pool_base_token_account: 5,
80
+ pool_quote_token_account: 6,
81
+ base_token_program: 9,
82
+ quote_token_program: 10,
83
+ };
84
+ for (const [field, index] of Object.entries(roles)) {
85
+ const key = field;
86
+ if (!e[key] || e[key] === zero)
87
+ e[key] = get(index);
88
+ }
89
+ }
49
90
  function fillPumpswapBuyAccounts(e, get) {
50
91
  fillPumpswapTradeCommon(e, get);
92
+ if (isCompactTrade(get))
93
+ return;
51
94
  const zero = Z();
52
95
  const a26 = get(26);
53
96
  if (a26 && a26 !== zero) {
@@ -55,7 +98,8 @@ function fillPumpswapBuyAccounts(e, get) {
55
98
  e.pool_v2 = get(24);
56
99
  if (!e.fee_recipient || e.fee_recipient === zero)
57
100
  e.fee_recipient = get(25);
58
- if (!e.fee_recipient_quote_token_account || e.fee_recipient_quote_token_account === zero) {
101
+ if (!e.fee_recipient_quote_token_account ||
102
+ e.fee_recipient_quote_token_account === zero) {
59
103
  e.fee_recipient_quote_token_account = a26;
60
104
  }
61
105
  return;
@@ -66,7 +110,8 @@ function fillPumpswapBuyAccounts(e, get) {
66
110
  e.pool_v2 = get(23);
67
111
  if (!e.fee_recipient || e.fee_recipient === zero)
68
112
  e.fee_recipient = get(24);
69
- if (!e.fee_recipient_quote_token_account || e.fee_recipient_quote_token_account === zero) {
113
+ if (!e.fee_recipient_quote_token_account ||
114
+ e.fee_recipient_quote_token_account === zero) {
70
115
  e.fee_recipient_quote_token_account = a25;
71
116
  }
72
117
  return;
@@ -76,6 +121,8 @@ function fillPumpswapBuyAccounts(e, get) {
76
121
  }
77
122
  function fillPumpswapSellAccounts(e, get) {
78
123
  fillPumpswapTradeCommon(e, get);
124
+ if (isCompactTrade(get))
125
+ return;
79
126
  const zero = Z();
80
127
  const a25 = get(25);
81
128
  if (a25 && a25 !== zero) {
@@ -83,7 +130,8 @@ function fillPumpswapSellAccounts(e, get) {
83
130
  e.pool_v2 = get(23);
84
131
  if (!e.fee_recipient || e.fee_recipient === zero)
85
132
  e.fee_recipient = get(24);
86
- if (!e.fee_recipient_quote_token_account || e.fee_recipient_quote_token_account === zero) {
133
+ if (!e.fee_recipient_quote_token_account ||
134
+ e.fee_recipient_quote_token_account === zero) {
87
135
  e.fee_recipient_quote_token_account = a25;
88
136
  }
89
137
  return;
@@ -94,7 +142,8 @@ function fillPumpswapSellAccounts(e, get) {
94
142
  e.pool_v2 = get(21);
95
143
  if (!e.fee_recipient || e.fee_recipient === zero)
96
144
  e.fee_recipient = get(22);
97
- if (!e.fee_recipient_quote_token_account || e.fee_recipient_quote_token_account === zero) {
145
+ if (!e.fee_recipient_quote_token_account ||
146
+ e.fee_recipient_quote_token_account === zero) {
98
147
  e.fee_recipient_quote_token_account = a23;
99
148
  }
100
149
  return;
@@ -57,11 +57,15 @@ function fillRaydiumClmmIncreaseLiquidityAccounts(e, get) {
57
57
  const zero = Z();
58
58
  if (!e.user || e.user === zero)
59
59
  e.user = get(0);
60
+ if (!e.pool || e.pool === zero)
61
+ e.pool = get(2);
60
62
  }
61
63
  function fillRaydiumClmmDecreaseLiquidityAccounts(e, get) {
62
64
  const zero = Z();
63
65
  if (!e.user || e.user === zero)
64
66
  e.user = get(0);
67
+ if (!e.pool || e.pool === zero)
68
+ e.pool = get(3);
65
69
  }
66
70
  function fillRaydiumCpmmSwapAccounts(e, get) {
67
71
  const zero = Z();