sol-parser-sdk 0.5.9 → 0.5.11
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 +34 -8
- package/README_CN.md +32 -8
- package/dist/accounts/pumpswap.js +15 -2
- package/dist/core/account_fill_raydium.d.ts +1 -1
- package/dist/core/account_fill_raydium.js +5 -1
- package/dist/core/dex_event.d.ts +11 -0
- package/dist/grpc/async_event_queue.d.ts +19 -0
- package/dist/grpc/async_event_queue.js +73 -0
- package/dist/grpc/client.d.ts +15 -4
- package/dist/grpc/client.js +102 -64
- package/dist/grpc/geyser_connect.d.ts +7 -1
- package/dist/grpc/geyser_connect.js +7 -1
- package/dist/grpc/log_instr_dedup.js +30 -12
- package/dist/grpc/types.d.ts +5 -3
- package/dist/grpc/types.js +5 -2
- package/dist/index.d.ts +1 -1
- package/dist/instr/inner.js +37 -15
- package/dist/instr/meteora_dlmm_ix.js +130 -38
- package/dist/instr/orca_whirlpool_ix.js +2 -1
- package/dist/instr/pumpswap_ix.js +10 -0
- package/dist/instr/raydium_amm_v4_ix.js +59 -36
- package/dist/instr/raydium_cpmm_ix.js +2 -2
- package/dist/logs/discriminator_lut.js +6 -2
- package/dist/logs/meteora_dlmm.d.ts +1 -0
- package/dist/logs/meteora_dlmm.js +135 -11
- package/dist/logs/optimized_matcher.js +25 -10
- package/dist/logs/program_log_discriminators.d.ts +1 -0
- package/dist/logs/program_log_discriminators.js +2 -0
- package/dist/logs/pump_amm.js +90 -22
- package/dist/logs/raydium_amm.d.ts +2 -0
- package/dist/logs/raydium_amm.js +36 -0
- package/dist/logs/raydium_cpmm.d.ts +2 -0
- package/dist/logs/raydium_cpmm.js +43 -0
- package/dist/rpc_transaction.js +118 -26
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -16,12 +16,6 @@
|
|
|
16
16
|
<a href="https://discord.gg/vuazbGkqQE">Discord</a>
|
|
17
17
|
</p>
|
|
18
18
|
|
|
19
|
-
> ☕ **Support This Project**
|
|
20
|
-
>
|
|
21
|
-
> This SDK is completely free and open source. However, maintaining and continuously updating it requires significant AI computing resources and token consumption. If this SDK helps with your development, consider making a monthly SOL donation — any amount is appreciated and helps keep this project alive!
|
|
22
|
-
>
|
|
23
|
-
> **Donation Wallet:** `6oW7AXz1yRb57pYSxysuXnMs2aR1ha5rzGzReZ1MjPV8`
|
|
24
|
-
|
|
25
19
|
---
|
|
26
20
|
|
|
27
21
|
## Other language SDKs
|
|
@@ -81,7 +75,7 @@
|
|
|
81
75
|
**From npm**
|
|
82
76
|
|
|
83
77
|
```bash
|
|
84
|
-
npm install sol-parser-sdk@0.5.
|
|
78
|
+
npm install sol-parser-sdk@0.5.11
|
|
85
79
|
```
|
|
86
80
|
|
|
87
81
|
**From source** (folder may be named `sol-parser-sdk-ts` in a monorepo)
|
|
@@ -153,6 +147,37 @@ const sub = await client.subscribeTransactions(filter, {
|
|
|
153
147
|
console.log("subscribed", sub.id);
|
|
154
148
|
```
|
|
155
149
|
|
|
150
|
+
### Long-running low-latency DEX subscriptions
|
|
151
|
+
|
|
152
|
+
The public API remains queue-based, matching the Rust SDK's `subscribe_dex_events` shape. The Node
|
|
153
|
+
subscription is an async iterable instead of Rust's `ArrayQueue`, while ring-buffer dequeue,
|
|
154
|
+
Yellowstone update parsing, HTTP/2 receive-window tuning, and reconnect behavior are handled inside
|
|
155
|
+
the SDK:
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
import { YellowstoneGrpc, lowLatencyClientConfig } from "sol-parser-sdk";
|
|
159
|
+
|
|
160
|
+
const client = new YellowstoneGrpc(ENDPOINT, X_TOKEN, lowLatencyClientConfig());
|
|
161
|
+
const sub = await client.subscribeDexEvents(txFilters, accountFilters, eventTypeFilter);
|
|
162
|
+
|
|
163
|
+
void (async () => {
|
|
164
|
+
for await (const error of sub.errors) console.error("subscription error", error);
|
|
165
|
+
})();
|
|
166
|
+
|
|
167
|
+
for await (const event of sub) {
|
|
168
|
+
handleEvent(event);
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
If using `for await`, the default overflow behavior remains `drop-newest` for compatibility. A
|
|
173
|
+
tip-oriented consumer can choose `queueOverflowStrategy: "drop-oldest"` and monitor `sub.len()` and
|
|
174
|
+
`sub.dropped()`. Every overflow is counted and periodically reported through `sub.errors`.
|
|
175
|
+
|
|
176
|
+
No bounded in-memory stream can guarantee both zero loss and bounded latency when the consumer's
|
|
177
|
+
average processing rate is below the filtered input rate. Keep the loop body CPU-light, avoid
|
|
178
|
+
per-event synchronous logging, filter at the server, and persist or dispatch slow work outside the
|
|
179
|
+
consumer loop.
|
|
180
|
+
|
|
156
181
|
**Lighter path:** `parseLogsOnly(logs, signature, slot, …)` — no `transactionRaw`; use `applyAccountFillsToLogEvents` if you need filled accounts without full gRPC meta.
|
|
157
182
|
|
|
158
183
|
### 5. ShredStream (HTTP — not Yellowstone gRPC)
|
|
@@ -179,6 +204,7 @@ From the **package root** after `npm install`. Examples use `npx tsx` and load `
|
|
|
179
204
|
| 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) |
|
|
180
205
|
| 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) |
|
|
181
206
|
| **PumpFun** | | |
|
|
207
|
+
| 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) |
|
|
182
208
|
| 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) |
|
|
183
209
|
| 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) |
|
|
184
210
|
| 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) |
|
|
@@ -204,7 +230,7 @@ From the **package root** after `npm install`. Examples use `npx tsx` and load `
|
|
|
204
230
|
- `npm run example:shredstream:subscribe` → [shredstream_example.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/shredstream_example.ts)
|
|
205
231
|
- `npm run example:shredstream:pumpfun-json` → [shredstream_pumpfun_json.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/shredstream_pumpfun_json.ts)
|
|
206
232
|
|
|
207
|
-
**Env:** gRPC examples need **`GRPC_URL`** + **`GRPC_TOKEN`**. ShredStream uses **`SHREDSTREAM_URL`** / **`SHRED_URL`** or **`--url`**; `shredstream_pumpfun_json` also needs **`RPC_URL`** / **`--rpc`**. See **`.env.example`**.
|
|
233
|
+
**Env:** gRPC examples need **`GRPC_URL`** + **`GRPC_TOKEN`**. Exported shell values take precedence; `.env` supplies values that are not already present. ShredStream uses **`SHREDSTREAM_URL`** / **`SHRED_URL`** or **`--url`**; `shredstream_pumpfun_json` also needs **`RPC_URL`** / **`--rpc`**. See **`.env.example`**.
|
|
208
234
|
|
|
209
235
|
---
|
|
210
236
|
|
package/README_CN.md
CHANGED
|
@@ -16,12 +16,6 @@
|
|
|
16
16
|
<a href="https://discord.gg/vuazbGkqQE">Discord</a>
|
|
17
17
|
</p>
|
|
18
18
|
|
|
19
|
-
> ☕ **支持本项目**
|
|
20
|
-
>
|
|
21
|
-
> 本 SDK 完全免费且开源。但维护和持续更新需要消耗大量 AI 算力与 Token。如果这个 SDK 对您的开发有帮助,欢迎每月捐赠任意数量的 SOL,您的支持将帮助这个项目持续运行!
|
|
22
|
-
>
|
|
23
|
-
> **捐赠钱包:** `6oW7AXz1yRb57pYSxysuXnMs2aR1ha5rzGzReZ1MjPV8`
|
|
24
|
-
|
|
25
19
|
---
|
|
26
20
|
|
|
27
21
|
## 其他语言 SDK
|
|
@@ -81,7 +75,7 @@
|
|
|
81
75
|
**npm**
|
|
82
76
|
|
|
83
77
|
```bash
|
|
84
|
-
npm install sol-parser-sdk@0.5.
|
|
78
|
+
npm install sol-parser-sdk@0.5.11
|
|
85
79
|
```
|
|
86
80
|
|
|
87
81
|
**源码**(monorepo 里目录可能是 `sol-parser-sdk-ts`)
|
|
@@ -153,6 +147,35 @@ const sub = await client.subscribeTransactions(filter, {
|
|
|
153
147
|
console.log("subscribed", sub.id);
|
|
154
148
|
```
|
|
155
149
|
|
|
150
|
+
### 长时间运行的低延迟 DEX 订阅
|
|
151
|
+
|
|
152
|
+
公开 API 保持队列式调用,与 Rust SDK 的 `subscribe_dex_events` 形态一致。Node 使用异步
|
|
153
|
+
迭代器代替 Rust 的 `ArrayQueue`;环形队列出队、Yellowstone update 解析、HTTP/2 接收窗口
|
|
154
|
+
和重连优化全部由 SDK 内部完成:
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
import { YellowstoneGrpc, lowLatencyClientConfig } from "sol-parser-sdk";
|
|
158
|
+
|
|
159
|
+
const client = new YellowstoneGrpc(ENDPOINT, X_TOKEN, lowLatencyClientConfig());
|
|
160
|
+
const sub = await client.subscribeDexEvents(txFilters, accountFilters, eventTypeFilter);
|
|
161
|
+
|
|
162
|
+
void (async () => {
|
|
163
|
+
for await (const error of sub.errors) console.error("subscription error", error);
|
|
164
|
+
})();
|
|
165
|
+
|
|
166
|
+
for await (const event of sub) {
|
|
167
|
+
handleEvent(event);
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
若使用 `for await`,默认溢出策略仍是 `drop-newest`,以保持兼容。更重视贴近链尖的消费者
|
|
172
|
+
可以设置 `queueOverflowStrategy: "drop-oldest"`,并监控 `sub.len()` 和 `sub.dropped()`。
|
|
173
|
+
每次溢出都会计数,并定期通过 `sub.errors` 报告。
|
|
174
|
+
|
|
175
|
+
当消费者平均处理速度低于过滤后的入流速度时,任何有界内存流都无法同时保证零丢失和
|
|
176
|
+
有界延迟。消费循环应保持轻量,避免逐事件同步日志,在服务端尽量缩小过滤范围,并把
|
|
177
|
+
慢 I/O 的持久化或分发移出消费循环。
|
|
178
|
+
|
|
156
179
|
更轻量:仅用日志用 `parseLogsOnly`;要补账户可再配合 `applyAccountFillsToLogEvents`。
|
|
157
180
|
|
|
158
181
|
### 5. ShredStream(HTTP,不是 Yellowstone gRPC)
|
|
@@ -179,6 +202,7 @@ npx tsx examples/shredstream_example.ts -- --url=http://127.0.0.1:10800
|
|
|
179
202
|
| 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) |
|
|
180
203
|
| 调试:打印 `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) |
|
|
181
204
|
| **PumpFun** | | |
|
|
205
|
+
| 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) |
|
|
182
206
|
| 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) |
|
|
183
207
|
| 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) |
|
|
184
208
|
| 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) |
|
|
@@ -204,7 +228,7 @@ npx tsx examples/shredstream_example.ts -- --url=http://127.0.0.1:10800
|
|
|
204
228
|
- `npm run example:shredstream:subscribe` → [shredstream_example.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/shredstream_example.ts)
|
|
205
229
|
- `npm run example:shredstream:pumpfun-json` → [shredstream_pumpfun_json.ts](https://github.com/0xfnzero/sol-parser-sdk-nodejs/blob/main/examples/shredstream_pumpfun_json.ts)
|
|
206
230
|
|
|
207
|
-
**环境变量:** gRPC 示例需要 **`GRPC_URL`**、**`GRPC_TOKEN
|
|
231
|
+
**环境变量:** gRPC 示例需要 **`GRPC_URL`**、**`GRPC_TOKEN`**。已 export 的 shell 环境变量优先,`.env` 只补充尚未设置的值。ShredStream 使用 **`SHREDSTREAM_URL`** / **`SHRED_URL`** 或 **`--url`**;**`shredstream_pumpfun_json`** 另需 **`RPC_URL`** / **`--rpc`**。详见 **`.env.example`**。
|
|
208
232
|
|
|
209
233
|
---
|
|
210
234
|
|
|
@@ -11,7 +11,8 @@ const program_ids_js_1 = require("../instr/program_ids.js");
|
|
|
11
11
|
const GLOBAL_DISC = Uint8Array.from([149, 8, 156, 202, 160, 252, 176, 217]);
|
|
12
12
|
const POOL_DISC = Uint8Array.from([241, 154, 109, 4, 17, 177, 109, 188]);
|
|
13
13
|
const GLOBAL_BODY = 634;
|
|
14
|
-
const
|
|
14
|
+
const POOL_LEGACY_BODY = 244;
|
|
15
|
+
const POOL_BODY = 253;
|
|
15
16
|
function isGlobalConfigAccount(data) {
|
|
16
17
|
return (0, utils_js_1.hasDiscriminator)(data, GLOBAL_DISC);
|
|
17
18
|
}
|
|
@@ -103,8 +104,11 @@ function parsePumpswapGlobalConfig(account, metadata) {
|
|
|
103
104
|
return { PumpSwapGlobalConfigAccount: ev };
|
|
104
105
|
}
|
|
105
106
|
function parsePumpswapPool(account, metadata) {
|
|
106
|
-
if (account.data.length < 8 +
|
|
107
|
+
if (account.data.length < 8 + POOL_LEGACY_BODY)
|
|
107
108
|
return null;
|
|
109
|
+
if (account.data.length !== 8 + POOL_LEGACY_BODY && account.data.length < 8 + POOL_BODY) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
108
112
|
if (!isPoolAccount(account.data))
|
|
109
113
|
return null;
|
|
110
114
|
const d = account.data.subarray(8);
|
|
@@ -156,6 +160,14 @@ function parsePumpswapPool(account, metadata) {
|
|
|
156
160
|
const cashback = (0, binary_js_1.readU8)(d, o);
|
|
157
161
|
if (cashback === null)
|
|
158
162
|
return null;
|
|
163
|
+
o += 1;
|
|
164
|
+
let virtual_quote_reserves = 0n;
|
|
165
|
+
if (d.length >= POOL_BODY) {
|
|
166
|
+
const virtual = (0, binary_js_1.readU128LE)(d, o);
|
|
167
|
+
if (virtual === null)
|
|
168
|
+
return null;
|
|
169
|
+
virtual_quote_reserves = BigInt.asIntN(128, virtual);
|
|
170
|
+
}
|
|
159
171
|
const pool = {
|
|
160
172
|
pool_bump,
|
|
161
173
|
index,
|
|
@@ -169,6 +181,7 @@ function parsePumpswapPool(account, metadata) {
|
|
|
169
181
|
coin_creator,
|
|
170
182
|
is_mayhem_mode: mayhem !== 0,
|
|
171
183
|
is_cashback_coin: cashback !== 0,
|
|
184
|
+
virtual_quote_reserves,
|
|
172
185
|
};
|
|
173
186
|
const ev = {
|
|
174
187
|
metadata,
|
|
@@ -11,7 +11,7 @@ export declare function fillRaydiumClmmOpenPositionWithTokenExtNftAccounts(e: Ra
|
|
|
11
11
|
export declare function fillRaydiumClmmClosePositionAccounts(e: RaydiumClmmClosePositionEvent, get: (i: number) => string): void;
|
|
12
12
|
export declare function fillRaydiumClmmIncreaseLiquidityAccounts(e: RaydiumClmmIncreaseLiquidityEvent, get: (i: number) => string): void;
|
|
13
13
|
export declare function fillRaydiumClmmDecreaseLiquidityAccounts(e: RaydiumClmmDecreaseLiquidityEvent, get: (i: number) => string): void;
|
|
14
|
-
export declare function fillRaydiumCpmmSwapAccounts(
|
|
14
|
+
export declare function fillRaydiumCpmmSwapAccounts(e: RaydiumCpmmSwapEvent, get: (i: number) => string): void;
|
|
15
15
|
export declare function fillRaydiumCpmmDepositAccounts(e: RaydiumCpmmDepositEvent, get: (i: number) => string): void;
|
|
16
16
|
export declare function fillRaydiumCpmmWithdrawAccounts(e: RaydiumCpmmWithdrawEvent, get: (i: number) => string): void;
|
|
17
17
|
export declare function fillRaydiumCpmmInitializeAccounts(e: RaydiumCpmmInitializeEvent, get: (i: number) => string): void;
|
|
@@ -63,7 +63,11 @@ function fillRaydiumClmmDecreaseLiquidityAccounts(e, get) {
|
|
|
63
63
|
if (!e.user || e.user === zero)
|
|
64
64
|
e.user = get(0);
|
|
65
65
|
}
|
|
66
|
-
function fillRaydiumCpmmSwapAccounts(
|
|
66
|
+
function fillRaydiumCpmmSwapAccounts(e, get) {
|
|
67
|
+
const zero = Z();
|
|
68
|
+
if (!e.pool_id || e.pool_id === zero)
|
|
69
|
+
e.pool_id = get(3);
|
|
70
|
+
}
|
|
67
71
|
function fillRaydiumCpmmDepositAccounts(e, get) {
|
|
68
72
|
const zero = Z();
|
|
69
73
|
if (!e.user || e.user === zero)
|
package/dist/core/dex_event.d.ts
CHANGED
|
@@ -480,6 +480,11 @@ export interface PumpSwapBuyEvent {
|
|
|
480
480
|
/** 与 `PumpSwapBuyEvent`:PUMP_CASHBACK / IDL */
|
|
481
481
|
cashback_fee_basis_points: bigint;
|
|
482
482
|
cashback: bigint;
|
|
483
|
+
buyback_fee_basis_points: bigint;
|
|
484
|
+
buyback_fee: bigint;
|
|
485
|
+
virtual_quote_reserves: bigint;
|
|
486
|
+
can_boost: boolean;
|
|
487
|
+
base_supply: bigint;
|
|
483
488
|
/** 由 fees 指令数据填充(见 `fillDataRpc`) */
|
|
484
489
|
is_pump_pool: boolean;
|
|
485
490
|
/** 自指令账户填充(account_fillers/pumpswap) */
|
|
@@ -522,6 +527,11 @@ export interface PumpSwapSellEvent {
|
|
|
522
527
|
coin_creator_fee: bigint;
|
|
523
528
|
cashback_fee_basis_points: bigint;
|
|
524
529
|
cashback: bigint;
|
|
530
|
+
buyback_fee_basis_points: bigint;
|
|
531
|
+
buyback_fee: bigint;
|
|
532
|
+
virtual_quote_reserves: bigint;
|
|
533
|
+
can_boost: boolean;
|
|
534
|
+
base_supply: bigint;
|
|
525
535
|
is_pump_pool: boolean;
|
|
526
536
|
base_mint: string;
|
|
527
537
|
quote_mint: string;
|
|
@@ -1432,6 +1442,7 @@ export interface PumpSwapPool {
|
|
|
1432
1442
|
coin_creator: string;
|
|
1433
1443
|
is_mayhem_mode: boolean;
|
|
1434
1444
|
is_cashback_coin: boolean;
|
|
1445
|
+
virtual_quote_reserves: bigint;
|
|
1435
1446
|
}
|
|
1436
1447
|
export interface PumpSwapPoolAccountEvent {
|
|
1437
1448
|
metadata: EventMetadata;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type EventQueueOverflowStrategy = "drop-newest" | "drop-oldest";
|
|
2
|
+
/** Internal O(1) queue used by the public async-iterable subscription. */
|
|
3
|
+
export declare class AsyncEventQueue<T> implements AsyncIterable<T>, AsyncIterator<T> {
|
|
4
|
+
private readonly maxSize;
|
|
5
|
+
private readonly overflowStrategy;
|
|
6
|
+
private readonly items;
|
|
7
|
+
private readonly waiters;
|
|
8
|
+
private closed;
|
|
9
|
+
private droppedCount;
|
|
10
|
+
private head;
|
|
11
|
+
private size;
|
|
12
|
+
constructor(maxSize: number, overflowStrategy?: EventQueueOverflowStrategy);
|
|
13
|
+
push(item: T): boolean;
|
|
14
|
+
len(): number;
|
|
15
|
+
dropped(): number;
|
|
16
|
+
close(): void;
|
|
17
|
+
next(): Promise<IteratorResult<T>>;
|
|
18
|
+
[Symbol.asyncIterator](): AsyncIterator<T>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AsyncEventQueue = void 0;
|
|
4
|
+
/** Internal O(1) queue used by the public async-iterable subscription. */
|
|
5
|
+
class AsyncEventQueue {
|
|
6
|
+
maxSize;
|
|
7
|
+
overflowStrategy;
|
|
8
|
+
items;
|
|
9
|
+
waiters = [];
|
|
10
|
+
closed = false;
|
|
11
|
+
droppedCount = 0;
|
|
12
|
+
head = 0;
|
|
13
|
+
size = 0;
|
|
14
|
+
constructor(maxSize, overflowStrategy = "drop-newest") {
|
|
15
|
+
this.maxSize = maxSize;
|
|
16
|
+
this.overflowStrategy = overflowStrategy;
|
|
17
|
+
if (!Number.isInteger(maxSize) || maxSize < 1) {
|
|
18
|
+
throw new RangeError("AsyncEventQueue maxSize must be a positive integer");
|
|
19
|
+
}
|
|
20
|
+
this.items = new Array(maxSize);
|
|
21
|
+
}
|
|
22
|
+
push(item) {
|
|
23
|
+
if (this.closed)
|
|
24
|
+
return false;
|
|
25
|
+
const waiter = this.waiters.shift();
|
|
26
|
+
if (waiter) {
|
|
27
|
+
waiter({ value: item, done: false });
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
if (this.size < this.maxSize) {
|
|
31
|
+
this.items[(this.head + this.size) % this.maxSize] = item;
|
|
32
|
+
this.size++;
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
this.droppedCount++;
|
|
36
|
+
if (this.overflowStrategy === "drop-oldest") {
|
|
37
|
+
this.items[this.head] = item;
|
|
38
|
+
this.head = (this.head + 1) % this.maxSize;
|
|
39
|
+
}
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
len() {
|
|
43
|
+
return this.size;
|
|
44
|
+
}
|
|
45
|
+
dropped() {
|
|
46
|
+
return this.droppedCount;
|
|
47
|
+
}
|
|
48
|
+
close() {
|
|
49
|
+
if (this.closed)
|
|
50
|
+
return;
|
|
51
|
+
this.closed = true;
|
|
52
|
+
for (const waiter of this.waiters.splice(0)) {
|
|
53
|
+
waiter({ value: undefined, done: true });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
next() {
|
|
57
|
+
if (this.size > 0) {
|
|
58
|
+
const item = this.items[this.head];
|
|
59
|
+
this.items[this.head] = undefined;
|
|
60
|
+
this.head = (this.head + 1) % this.maxSize;
|
|
61
|
+
this.size--;
|
|
62
|
+
return Promise.resolve({ value: item, done: false });
|
|
63
|
+
}
|
|
64
|
+
if (this.closed) {
|
|
65
|
+
return Promise.resolve({ value: undefined, done: true });
|
|
66
|
+
}
|
|
67
|
+
return new Promise((resolve) => this.waiters.push(resolve));
|
|
68
|
+
}
|
|
69
|
+
[Symbol.asyncIterator]() {
|
|
70
|
+
return this;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
exports.AsyncEventQueue = AsyncEventQueue;
|
package/dist/grpc/client.d.ts
CHANGED
|
@@ -3,13 +3,25 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { CommitmentLevel } from "@triton-one/yellowstone-grpc";
|
|
5
5
|
import type { DexEvent } from "../core/dex_event.js";
|
|
6
|
+
import { type EventQueueOverflowStrategy } from "./async_event_queue.js";
|
|
6
7
|
import { type AccountFilter, type ClientConfig, type EventTypeFilter, type TransactionFilter, type SubscribeCallbacks } from "./types.js";
|
|
7
8
|
export { SubscribeCallbacks };
|
|
9
|
+
export type { EventQueueOverflowStrategy } from "./async_event_queue.js";
|
|
8
10
|
export interface DexEventSubscription extends AsyncIterable<DexEvent> {
|
|
9
11
|
id: string;
|
|
10
12
|
errors: AsyncIterable<Error>;
|
|
11
13
|
cancel(): void;
|
|
12
14
|
next(): Promise<IteratorResult<DexEvent>>;
|
|
15
|
+
len(): number;
|
|
16
|
+
dropped(): number;
|
|
17
|
+
}
|
|
18
|
+
export interface SubscribeDexEventsOptions {
|
|
19
|
+
autoReconnect?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Queue behavior when an async-iterator consumer cannot keep up. The default
|
|
22
|
+
* preserves the existing behavior; `drop-oldest` favors staying near chain tip.
|
|
23
|
+
*/
|
|
24
|
+
queueOverflowStrategy?: EventQueueOverflowStrategy;
|
|
13
25
|
}
|
|
14
26
|
/** Yellowstone gRPC 客户端包装器 */
|
|
15
27
|
export declare class YellowstoneGrpc {
|
|
@@ -41,6 +53,7 @@ export declare class YellowstoneGrpc {
|
|
|
41
53
|
private static protobufNumber;
|
|
42
54
|
private static timestampToMicros;
|
|
43
55
|
private parseAccountEvent;
|
|
56
|
+
private parseAccountEventRaw;
|
|
44
57
|
private initialSubscribeRequest;
|
|
45
58
|
/** 订阅交易 */
|
|
46
59
|
subscribeTransactions(filter: TransactionFilter, callbacks: SubscribeCallbacks): Promise<{
|
|
@@ -51,11 +64,9 @@ export declare class YellowstoneGrpc {
|
|
|
51
64
|
* 订阅并直接产出 `DexEvent`。
|
|
52
65
|
*
|
|
53
66
|
* 交易更新走统一交易解析(外层/内层指令 + 日志 + 数据填充);账户更新走 `parseAccountUnified`。
|
|
54
|
-
*
|
|
67
|
+
* 事件队列满时按配置丢弃事件,避免回调阻塞 gRPC 读循环并让丢弃可观测。
|
|
55
68
|
*/
|
|
56
|
-
subscribeDexEvents(transactionFilters?: TransactionFilter[], accountFilters?: AccountFilter[], eventTypeFilter?: EventTypeFilter, options?:
|
|
57
|
-
autoReconnect?: boolean;
|
|
58
|
-
}): Promise<DexEventSubscription>;
|
|
69
|
+
subscribeDexEvents(transactionFilters?: TransactionFilter[], accountFilters?: AccountFilter[], eventTypeFilter?: EventTypeFilter, options?: SubscribeDexEventsOptions): Promise<DexEventSubscription>;
|
|
59
70
|
/** 取消订阅 */
|
|
60
71
|
unsubscribe(subId: string): void;
|
|
61
72
|
/** 动态更新当前 DEX 订阅过滤器(与 Rust update_subscription 语义对齐)。 */
|