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/dist/grpc/client.js
CHANGED
|
@@ -45,51 +45,18 @@ const bs58_1 = __importDefault(require("bs58"));
|
|
|
45
45
|
const metadata_js_1 = require("../core/metadata.js");
|
|
46
46
|
const mod_js_1 = require("../accounts/mod.js");
|
|
47
47
|
const geyser_connect_js_1 = require("./geyser_connect.js");
|
|
48
|
+
const async_event_queue_js_1 = require("./async_event_queue.js");
|
|
48
49
|
const order_buffer_js_1 = require("./order_buffer.js");
|
|
49
50
|
const subscribe_builder_js_1 = require("./subscribe_builder.js");
|
|
50
51
|
const yellowstone_parse_js_1 = require("./yellowstone_parse.js");
|
|
51
52
|
const types_js_1 = require("./types.js");
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
push(item) {
|
|
61
|
-
if (this.closed)
|
|
62
|
-
return;
|
|
63
|
-
const waiter = this.waiters.shift();
|
|
64
|
-
if (waiter) {
|
|
65
|
-
waiter({ value: item, done: false });
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
if (this.items.length < this.maxSize) {
|
|
69
|
-
this.items.push(item);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
close() {
|
|
73
|
-
if (this.closed)
|
|
74
|
-
return;
|
|
75
|
-
this.closed = true;
|
|
76
|
-
for (const waiter of this.waiters.splice(0)) {
|
|
77
|
-
waiter({ value: undefined, done: true });
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
next() {
|
|
81
|
-
const item = this.items.shift();
|
|
82
|
-
if (item !== undefined) {
|
|
83
|
-
return Promise.resolve({ value: item, done: false });
|
|
84
|
-
}
|
|
85
|
-
if (this.closed) {
|
|
86
|
-
return Promise.resolve({ value: undefined, done: true });
|
|
87
|
-
}
|
|
88
|
-
return new Promise((resolve) => this.waiters.push(resolve));
|
|
89
|
-
}
|
|
90
|
-
[Symbol.asyncIterator]() {
|
|
91
|
-
return this;
|
|
92
|
-
}
|
|
53
|
+
function cancelSubscribeStream(stream) {
|
|
54
|
+
if (!stream)
|
|
55
|
+
return;
|
|
56
|
+
// grpc-js emits CANCELLED through `error`; guard the short setup window before
|
|
57
|
+
// the normal lifecycle listeners have been installed.
|
|
58
|
+
stream.once("error", () => { });
|
|
59
|
+
stream.cancel();
|
|
93
60
|
}
|
|
94
61
|
/** Yellowstone gRPC 客户端包装器 */
|
|
95
62
|
class YellowstoneGrpc {
|
|
@@ -105,6 +72,9 @@ class YellowstoneGrpc {
|
|
|
105
72
|
...gc,
|
|
106
73
|
keepAliveIntervalMs: config.keep_alive_interval_ms,
|
|
107
74
|
keepAliveTimeoutMs: config.keep_alive_timeout_ms,
|
|
75
|
+
initialReconnectBackoffMs: config.retry_delay_ms,
|
|
76
|
+
maxReconnectBackoffMs: 60_000,
|
|
77
|
+
flowControlWindowBytes: config.flow_control_window_bytes,
|
|
108
78
|
}));
|
|
109
79
|
}
|
|
110
80
|
/** 连接到 gRPC 服务器 */
|
|
@@ -302,6 +272,22 @@ class YellowstoneGrpc {
|
|
|
302
272
|
const metadata = (0, metadata_js_1.makeMetadata)(signatureBytes.length > 0 ? bs58_1.default.encode(signatureBytes) : "", Number(update.slot), 0, blockTimeUs, grpcRecvUs);
|
|
303
273
|
return (0, mod_js_1.parseAccountUnified)(account, metadata, eventTypeFilter);
|
|
304
274
|
}
|
|
275
|
+
parseAccountEventRaw(update, grpcRecvUs, eventTypeFilter, blockTimeUs) {
|
|
276
|
+
const acc = update.account;
|
|
277
|
+
if (!acc)
|
|
278
|
+
return null;
|
|
279
|
+
const signatureBytes = YellowstoneGrpc.toBytes(acc.txnSignature);
|
|
280
|
+
const account = {
|
|
281
|
+
pubkey: bs58_1.default.encode(YellowstoneGrpc.toBytes(acc.pubkey)),
|
|
282
|
+
executable: acc.executable,
|
|
283
|
+
lamports: YellowstoneGrpc.toBigInt(acc.lamports),
|
|
284
|
+
owner: bs58_1.default.encode(YellowstoneGrpc.toBytes(acc.owner)),
|
|
285
|
+
rent_epoch: YellowstoneGrpc.toBigInt(acc.rentEpoch),
|
|
286
|
+
data: YellowstoneGrpc.toBytes(acc.data),
|
|
287
|
+
};
|
|
288
|
+
const metadata = (0, metadata_js_1.makeMetadata)(signatureBytes.length > 0 ? bs58_1.default.encode(signatureBytes) : "", YellowstoneGrpc.protobufNumber(update.slot), 0, blockTimeUs, grpcRecvUs);
|
|
289
|
+
return (0, mod_js_1.parseAccountUnified)(account, metadata, eventTypeFilter);
|
|
290
|
+
}
|
|
305
291
|
initialSubscribeRequest(filter) {
|
|
306
292
|
return {
|
|
307
293
|
transactions: {
|
|
@@ -332,7 +318,7 @@ class YellowstoneGrpc {
|
|
|
332
318
|
const streamHolder = { current: null };
|
|
333
319
|
const cancel = () => {
|
|
334
320
|
isCancelled = true;
|
|
335
|
-
streamHolder.current
|
|
321
|
+
cancelSubscribeStream(streamHolder.current);
|
|
336
322
|
streamHolder.current = null;
|
|
337
323
|
};
|
|
338
324
|
this.subscribers.set(id, { filter, callbacks, cancel });
|
|
@@ -344,6 +330,10 @@ class YellowstoneGrpc {
|
|
|
344
330
|
while (!isCancelled) {
|
|
345
331
|
try {
|
|
346
332
|
const stream = await this.client.subscribe();
|
|
333
|
+
if (isCancelled) {
|
|
334
|
+
cancelSubscribeStream(stream);
|
|
335
|
+
break;
|
|
336
|
+
}
|
|
347
337
|
streamHolder.current = stream;
|
|
348
338
|
await new Promise((resolve, reject) => {
|
|
349
339
|
stream.write(this.initialSubscribeRequest(filter), (err) => {
|
|
@@ -353,7 +343,6 @@ class YellowstoneGrpc {
|
|
|
353
343
|
resolve();
|
|
354
344
|
});
|
|
355
345
|
});
|
|
356
|
-
backoffMs = this.config.retry_delay_ms;
|
|
357
346
|
await new Promise((resolve, reject) => {
|
|
358
347
|
const cleanup = () => {
|
|
359
348
|
stream.removeAllListeners();
|
|
@@ -364,6 +353,7 @@ class YellowstoneGrpc {
|
|
|
364
353
|
stream.on("data", (update) => {
|
|
365
354
|
if (isCancelled)
|
|
366
355
|
return;
|
|
356
|
+
backoffMs = this.config.retry_delay_ms;
|
|
367
357
|
if (update.ping) {
|
|
368
358
|
stream.write(this.subscribePingPongRequest(), (werr) => {
|
|
369
359
|
if (werr && callbacks.onError && !isCancelled) {
|
|
@@ -396,6 +386,8 @@ class YellowstoneGrpc {
|
|
|
396
386
|
catch (err) {
|
|
397
387
|
if (isCancelled)
|
|
398
388
|
break;
|
|
389
|
+
cancelSubscribeStream(streamHolder.current);
|
|
390
|
+
streamHolder.current = null;
|
|
399
391
|
const e = err instanceof Error ? err : new Error(String(err));
|
|
400
392
|
callbacks.onError?.(e);
|
|
401
393
|
if (!autoReconnect)
|
|
@@ -415,7 +407,7 @@ class YellowstoneGrpc {
|
|
|
415
407
|
}
|
|
416
408
|
}
|
|
417
409
|
finally {
|
|
418
|
-
streamHolder.current
|
|
410
|
+
cancelSubscribeStream(streamHolder.current);
|
|
419
411
|
streamHolder.current = null;
|
|
420
412
|
this.subscribers.delete(id);
|
|
421
413
|
}
|
|
@@ -432,15 +424,26 @@ class YellowstoneGrpc {
|
|
|
432
424
|
* 订阅并直接产出 `DexEvent`。
|
|
433
425
|
*
|
|
434
426
|
* 交易更新走统一交易解析(外层/内层指令 + 日志 + 数据填充);账户更新走 `parseAccountUnified`。
|
|
435
|
-
*
|
|
427
|
+
* 事件队列满时按配置丢弃事件,避免回调阻塞 gRPC 读循环并让丢弃可观测。
|
|
436
428
|
*/
|
|
437
429
|
async subscribeDexEvents(transactionFilters = [], accountFilters = [], eventTypeFilter, options) {
|
|
438
430
|
await this.connect();
|
|
439
431
|
const id = `dex_${Date.now()}_${Math.random().toString(36).slice(2)}`;
|
|
440
|
-
const events = new AsyncEventQueue(Math.max(1, this.config.buffer_size));
|
|
441
|
-
const errors = new AsyncEventQueue(Math.max(1, this.config.buffer_size));
|
|
432
|
+
const events = new async_event_queue_js_1.AsyncEventQueue(Math.max(1, this.config.buffer_size), options?.queueOverflowStrategy);
|
|
433
|
+
const errors = new async_event_queue_js_1.AsyncEventQueue(Math.max(1, this.config.buffer_size));
|
|
442
434
|
const order = new order_buffer_js_1.OrderDispatcher(this.config);
|
|
443
|
-
|
|
435
|
+
let nextDropWarningAt = 0;
|
|
436
|
+
const reportError = (error) => errors.push(error);
|
|
437
|
+
const emitEvent = (event) => {
|
|
438
|
+
if (events.push(event))
|
|
439
|
+
return;
|
|
440
|
+
const now = Date.now();
|
|
441
|
+
if (now < nextDropWarningAt)
|
|
442
|
+
return;
|
|
443
|
+
nextDropWarningAt = now + 10_000;
|
|
444
|
+
reportError(new Error(`Dex event queue full; dropped=${events.dropped()} buffer_size=${this.config.buffer_size} ` +
|
|
445
|
+
`strategy=${options?.queueOverflowStrategy ?? "drop-newest"}`));
|
|
446
|
+
};
|
|
444
447
|
let flushTimer;
|
|
445
448
|
if (order.needsTimer) {
|
|
446
449
|
const intervalMs = this.config.order_mode === "MicroBatch"
|
|
@@ -452,9 +455,27 @@ class YellowstoneGrpc {
|
|
|
452
455
|
let currentTransactionFilters = transactionFilters;
|
|
453
456
|
let currentAccountFilters = accountFilters;
|
|
454
457
|
const streamHolder = { current: null };
|
|
458
|
+
let cancelReconnectDelay;
|
|
459
|
+
const waitBeforeReconnect = (delayMs) => new Promise((resolve) => {
|
|
460
|
+
let settled = false;
|
|
461
|
+
const finish = () => {
|
|
462
|
+
if (settled)
|
|
463
|
+
return;
|
|
464
|
+
settled = true;
|
|
465
|
+
clearTimeout(timer);
|
|
466
|
+
if (cancelReconnectDelay === finish)
|
|
467
|
+
cancelReconnectDelay = undefined;
|
|
468
|
+
resolve();
|
|
469
|
+
};
|
|
470
|
+
const timer = setTimeout(finish, delayMs);
|
|
471
|
+
cancelReconnectDelay = finish;
|
|
472
|
+
if (isCancelled)
|
|
473
|
+
finish();
|
|
474
|
+
});
|
|
455
475
|
const cancel = () => {
|
|
456
476
|
isCancelled = true;
|
|
457
|
-
|
|
477
|
+
cancelReconnectDelay?.();
|
|
478
|
+
cancelSubscribeStream(streamHolder.current);
|
|
458
479
|
streamHolder.current = null;
|
|
459
480
|
if (flushTimer)
|
|
460
481
|
clearInterval(flushTimer);
|
|
@@ -485,6 +506,10 @@ class YellowstoneGrpc {
|
|
|
485
506
|
while (!isCancelled) {
|
|
486
507
|
try {
|
|
487
508
|
const stream = await this.client.subscribe();
|
|
509
|
+
if (isCancelled) {
|
|
510
|
+
cancelSubscribeStream(stream);
|
|
511
|
+
break;
|
|
512
|
+
}
|
|
488
513
|
streamHolder.current = stream;
|
|
489
514
|
await new Promise((resolve, reject) => {
|
|
490
515
|
stream.write((0, subscribe_builder_js_1.buildSubscribeRequest)(currentTransactionFilters, currentAccountFilters), (err) => {
|
|
@@ -494,7 +519,6 @@ class YellowstoneGrpc {
|
|
|
494
519
|
resolve();
|
|
495
520
|
});
|
|
496
521
|
});
|
|
497
|
-
backoffMs = this.config.retry_delay_ms;
|
|
498
522
|
await new Promise((resolve, reject) => {
|
|
499
523
|
const cleanup = () => {
|
|
500
524
|
stream.removeAllListeners();
|
|
@@ -505,33 +529,44 @@ class YellowstoneGrpc {
|
|
|
505
529
|
stream.on("data", (update) => {
|
|
506
530
|
if (isCancelled)
|
|
507
531
|
return;
|
|
508
|
-
|
|
532
|
+
backoffMs = this.config.retry_delay_ms;
|
|
533
|
+
if (order.needsTimer)
|
|
534
|
+
order.flushDue(emitEvent);
|
|
509
535
|
if (update.ping) {
|
|
510
536
|
stream.write(this.subscribePingPongRequest(), (werr) => {
|
|
511
537
|
if (werr && !isCancelled) {
|
|
512
|
-
|
|
538
|
+
reportError(werr instanceof Error ? werr : new Error(String(werr)));
|
|
513
539
|
}
|
|
514
540
|
});
|
|
515
541
|
return;
|
|
516
542
|
}
|
|
517
543
|
try {
|
|
518
544
|
const grpcRecvUs = Math.floor(Date.now() * 1000);
|
|
519
|
-
const
|
|
520
|
-
const
|
|
545
|
+
const blockTimeUs = YellowstoneGrpc.timestampToMicros(update.createdAt ?? update.created_at);
|
|
546
|
+
const txUpdate = update.transaction;
|
|
547
|
+
const tx = txUpdate?.transaction;
|
|
521
548
|
if (tx) {
|
|
522
|
-
const
|
|
549
|
+
const slot = txUpdate?.slot ?? 0n;
|
|
550
|
+
const fallbackSlot = YellowstoneGrpc.protobufNumber(slot);
|
|
523
551
|
const fallbackTxIndex = YellowstoneGrpc.protobufNumber(tx.index ?? 0);
|
|
524
|
-
const
|
|
552
|
+
const txInfo = {
|
|
553
|
+
signature: tx.signature,
|
|
554
|
+
isVote: tx.isVote,
|
|
555
|
+
transactionRaw: tx.transaction,
|
|
556
|
+
metaRaw: tx.meta,
|
|
557
|
+
index: (tx.index ?? 0n),
|
|
558
|
+
};
|
|
559
|
+
const txEvents = (0, yellowstone_parse_js_1.parseDexEventsFromGrpcTransactionInfo)(txInfo, slot, { blockTimeUs, grpcRecvUs, eventTypeFilter });
|
|
525
560
|
order.pushTransactionEvents(txEvents, fallbackSlot, fallbackTxIndex, emitEvent);
|
|
526
561
|
}
|
|
527
|
-
if (
|
|
528
|
-
const ev = this.
|
|
562
|
+
if (update.account) {
|
|
563
|
+
const ev = this.parseAccountEventRaw(update.account, grpcRecvUs, eventTypeFilter, blockTimeUs);
|
|
529
564
|
if (ev)
|
|
530
565
|
emitEvent(ev);
|
|
531
566
|
}
|
|
532
567
|
}
|
|
533
568
|
catch (err) {
|
|
534
|
-
|
|
569
|
+
reportError(err instanceof Error ? err : new Error(String(err)));
|
|
535
570
|
}
|
|
536
571
|
});
|
|
537
572
|
stream.on("error", (err) => {
|
|
@@ -547,25 +582,28 @@ class YellowstoneGrpc {
|
|
|
547
582
|
catch (err) {
|
|
548
583
|
if (isCancelled)
|
|
549
584
|
break;
|
|
550
|
-
|
|
585
|
+
cancelSubscribeStream(streamHolder.current);
|
|
586
|
+
streamHolder.current = null;
|
|
587
|
+
reportError(err instanceof Error ? err : new Error(String(err)));
|
|
551
588
|
if (!autoReconnect)
|
|
552
589
|
break;
|
|
553
|
-
await
|
|
590
|
+
await waitBeforeReconnect(backoffMs);
|
|
554
591
|
backoffMs = Math.min(backoffMs * 2, maxBackoffMs);
|
|
555
592
|
continue;
|
|
556
593
|
}
|
|
557
594
|
if (isCancelled || !autoReconnect)
|
|
558
595
|
break;
|
|
559
|
-
await
|
|
596
|
+
await waitBeforeReconnect(backoffMs);
|
|
560
597
|
backoffMs = Math.min(backoffMs * 2, maxBackoffMs);
|
|
561
598
|
}
|
|
562
599
|
}
|
|
563
600
|
finally {
|
|
564
|
-
streamHolder.current
|
|
601
|
+
cancelSubscribeStream(streamHolder.current);
|
|
565
602
|
streamHolder.current = null;
|
|
566
603
|
if (flushTimer)
|
|
567
604
|
clearInterval(flushTimer);
|
|
568
|
-
|
|
605
|
+
if (!isCancelled)
|
|
606
|
+
order.flushAll(emitEvent);
|
|
569
607
|
events.close();
|
|
570
608
|
errors.close();
|
|
571
609
|
this.dexSubscribers.delete(id);
|
|
@@ -18,8 +18,14 @@ export interface GeyserConnectConfig {
|
|
|
18
18
|
keepAliveIntervalMs?: number;
|
|
19
19
|
/** gRPC keepalive 应答超时(毫秒) */
|
|
20
20
|
keepAliveTimeoutMs?: number;
|
|
21
|
+
/** gRPC 连接初始重试退避(毫秒) */
|
|
22
|
+
initialReconnectBackoffMs?: number;
|
|
23
|
+
/** gRPC 连接最大重试退避(毫秒) */
|
|
24
|
+
maxReconnectBackoffMs?: number;
|
|
25
|
+
/** HTTP/2 本地接收窗口(字节) */
|
|
26
|
+
flowControlWindowBytes?: number;
|
|
21
27
|
}
|
|
22
|
-
/**
|
|
28
|
+
/** 公共字段与 Rust `GeyserConnectConfig::default` 一致,并包含 Node gRPC 通道默认值。 */
|
|
23
29
|
export declare function defaultGeyserConnectConfig(): GeyserConnectConfig;
|
|
24
30
|
/** 与 `ClientConfig` / `grpc.keepalive_*` 对齐,用于长连接抗 NAT/负载均衡 idle 断开 */
|
|
25
31
|
export declare function geyserGrpcChannelOptions(config?: GeyserConnectConfig): ChannelOptions;
|
|
@@ -7,7 +7,7 @@ exports.defaultGeyserConnectConfig = defaultGeyserConnectConfig;
|
|
|
7
7
|
exports.geyserGrpcChannelOptions = geyserGrpcChannelOptions;
|
|
8
8
|
exports.connectYellowstoneGeyser = connectYellowstoneGeyser;
|
|
9
9
|
const yellowstone_grpc_1 = __importDefault(require("@triton-one/yellowstone-grpc"));
|
|
10
|
-
/**
|
|
10
|
+
/** 公共字段与 Rust `GeyserConnectConfig::default` 一致,并包含 Node gRPC 通道默认值。 */
|
|
11
11
|
function defaultGeyserConnectConfig() {
|
|
12
12
|
return {
|
|
13
13
|
connectTimeoutMs: 8000,
|
|
@@ -15,6 +15,9 @@ function defaultGeyserConnectConfig() {
|
|
|
15
15
|
xToken: undefined,
|
|
16
16
|
keepAliveIntervalMs: 30_000,
|
|
17
17
|
keepAliveTimeoutMs: 5000,
|
|
18
|
+
initialReconnectBackoffMs: 1000,
|
|
19
|
+
maxReconnectBackoffMs: 60_000,
|
|
20
|
+
flowControlWindowBytes: 1024 * 1024,
|
|
18
21
|
};
|
|
19
22
|
}
|
|
20
23
|
/** 与 `ClientConfig` / `grpc.keepalive_*` 对齐,用于长连接抗 NAT/负载均衡 idle 断开 */
|
|
@@ -29,6 +32,9 @@ function geyserGrpcChannelOptions(config = defaultGeyserConnectConfig()) {
|
|
|
29
32
|
"grpc.keepalive_timeout_ms": timeout,
|
|
30
33
|
/** 无活跃 RPC 时仍发 keepalive,避免长时间仅订阅时被中间设备掐断 */
|
|
31
34
|
"grpc.keepalive_permit_without_calls": 1,
|
|
35
|
+
"grpc.initial_reconnect_backoff_ms": config.initialReconnectBackoffMs,
|
|
36
|
+
"grpc.max_reconnect_backoff_ms": config.maxReconnectBackoffMs,
|
|
37
|
+
"grpc-node.flow_control_window": config.flowControlWindowBytes,
|
|
32
38
|
};
|
|
33
39
|
}
|
|
34
40
|
/**
|
|
@@ -62,7 +62,7 @@ function nextOccurrence(base, counts) {
|
|
|
62
62
|
counts.set(base, current + 1);
|
|
63
63
|
return current;
|
|
64
64
|
}
|
|
65
|
-
function dedupeKey(ev,
|
|
65
|
+
function dedupeKey(ev, occurrenceCounts) {
|
|
66
66
|
const name = eventName(ev);
|
|
67
67
|
const data = payload(ev);
|
|
68
68
|
if (!data)
|
|
@@ -70,7 +70,7 @@ function dedupeKey(ev, pumpfunLaneCounts) {
|
|
|
70
70
|
if (PUMPFUN_TRADE_NAMES.has(name)) {
|
|
71
71
|
const lane = ixLane(data.ix_name);
|
|
72
72
|
const base = `${data.mint}|${data.user}|${Boolean(data.is_buy)}|${lane}`;
|
|
73
|
-
const occurrence = nextOccurrence(base
|
|
73
|
+
const occurrence = nextOccurrence(`PumpFun|${base}`, occurrenceCounts);
|
|
74
74
|
return `PumpFunTrade|${base}|${occurrence}`;
|
|
75
75
|
}
|
|
76
76
|
switch (name) {
|
|
@@ -98,12 +98,28 @@ function dedupeKey(ev, pumpfunLaneCounts) {
|
|
|
98
98
|
return `PumpSwapLiquidityAdded|${data.pool}|${data.user}`;
|
|
99
99
|
case "PumpSwapLiquidityRemoved":
|
|
100
100
|
return `PumpSwapLiquidityRemoved|${data.pool}|${data.user}`;
|
|
101
|
-
case "RaydiumClmmSwap":
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
case "
|
|
106
|
-
|
|
101
|
+
case "RaydiumClmmSwap": {
|
|
102
|
+
const base = String(data.pool_state);
|
|
103
|
+
return `RaydiumClmmSwap|${base}|${nextOccurrence(`RaydiumClmm|${base}`, occurrenceCounts)}`;
|
|
104
|
+
}
|
|
105
|
+
case "RaydiumCpmmSwap": {
|
|
106
|
+
const base = String(data.pool_id);
|
|
107
|
+
return `RaydiumCpmmSwap|${base}|${nextOccurrence(`RaydiumCpmm|${base}`, occurrenceCounts)}`;
|
|
108
|
+
}
|
|
109
|
+
case "RaydiumAmmV4Swap": {
|
|
110
|
+
const base = data.max_amount_in !== 0n && data.max_amount_in !== 0
|
|
111
|
+
? `out|${data.amount_out}`
|
|
112
|
+
: `in|${data.amount_in}`;
|
|
113
|
+
return `RaydiumAmmV4Swap|${base}|${nextOccurrence(`RaydiumAmmV4|${base}`, occurrenceCounts)}`;
|
|
114
|
+
}
|
|
115
|
+
case "OrcaWhirlpoolSwap": {
|
|
116
|
+
const base = String(data.whirlpool);
|
|
117
|
+
return `OrcaWhirlpoolSwap|${base}|${nextOccurrence(`OrcaWhirlpool|${base}`, occurrenceCounts)}`;
|
|
118
|
+
}
|
|
119
|
+
case "MeteoraDlmmSwap": {
|
|
120
|
+
const base = `${data.pool}|${data.from}|${Boolean(data.swap_for_y)}`;
|
|
121
|
+
return `MeteoraDlmmSwap|${base}|${nextOccurrence(`MeteoraDlmm|${base}`, occurrenceCounts)}`;
|
|
122
|
+
}
|
|
107
123
|
default:
|
|
108
124
|
return null;
|
|
109
125
|
}
|
|
@@ -282,6 +298,8 @@ function mergeRaydiumAmmV4Swap(log, ix) {
|
|
|
282
298
|
"serum_vault_signer",
|
|
283
299
|
"user_source_token_account",
|
|
284
300
|
"user_destination_token_account",
|
|
301
|
+
"user_source_owner",
|
|
302
|
+
"amm",
|
|
285
303
|
]) {
|
|
286
304
|
fillString(log, key, ix);
|
|
287
305
|
}
|
|
@@ -376,16 +394,16 @@ function mergeGrpcInstructionIntoLog(logEvent, ixEvent) {
|
|
|
376
394
|
function dedupeLogInstructionEvents(logEvents, instructionEvents) {
|
|
377
395
|
const out = [];
|
|
378
396
|
const indexByKey = new Map();
|
|
379
|
-
const
|
|
380
|
-
const
|
|
397
|
+
const logOccurrenceCounts = new Map();
|
|
398
|
+
const ixOccurrenceCounts = new Map();
|
|
381
399
|
for (const ev of logEvents) {
|
|
382
|
-
const key = dedupeKey(ev,
|
|
400
|
+
const key = dedupeKey(ev, logOccurrenceCounts);
|
|
383
401
|
if (key)
|
|
384
402
|
indexByKey.set(key, out.length);
|
|
385
403
|
out.push(ev);
|
|
386
404
|
}
|
|
387
405
|
for (const ev of instructionEvents) {
|
|
388
|
-
const key = dedupeKey(ev,
|
|
406
|
+
const key = dedupeKey(ev, ixOccurrenceCounts);
|
|
389
407
|
if (!key) {
|
|
390
408
|
out.push(ev);
|
|
391
409
|
continue;
|
package/dist/grpc/types.d.ts
CHANGED
|
@@ -98,16 +98,18 @@ export interface ClientConfig {
|
|
|
98
98
|
keep_alive_interval_ms: number;
|
|
99
99
|
keep_alive_timeout_ms: number;
|
|
100
100
|
buffer_size: number;
|
|
101
|
+
/** Node gRPC HTTP/2 receive window. Larger values reduce stalls on bursty streams. */
|
|
102
|
+
flow_control_window_bytes?: number;
|
|
101
103
|
order_mode: OrderMode;
|
|
102
104
|
order_timeout_ms: number;
|
|
103
105
|
micro_batch_us: number;
|
|
104
106
|
}
|
|
105
|
-
/** 与 Rust `grpc::config` 中 `StreamingConfig`
|
|
107
|
+
/** 与 Rust `grpc::config` 中 `StreamingConfig` 别名一致,并包含可选 Node gRPC 参数。 */
|
|
106
108
|
export type StreamingConfig = ClientConfig;
|
|
107
109
|
export declare function defaultClientConfig(): ClientConfig;
|
|
108
|
-
/**
|
|
110
|
+
/** Rust `ClientConfig::low_latency` 的 Node 调优版本,使用更小的 JS 对象队列。 */
|
|
109
111
|
export declare function lowLatencyClientConfig(): ClientConfig;
|
|
110
|
-
/**
|
|
112
|
+
/** Rust `ClientConfig::high_throughput` 的 Node 调优版本,使用更小的 JS 对象队列。 */
|
|
111
113
|
export declare function highThroughputClientConfig(): ClientConfig;
|
|
112
114
|
export interface TransactionFilter {
|
|
113
115
|
account_include: string[];
|
package/dist/grpc/types.js
CHANGED
|
@@ -42,12 +42,13 @@ function defaultClientConfig() {
|
|
|
42
42
|
keep_alive_interval_ms: 30000,
|
|
43
43
|
keep_alive_timeout_ms: 5000,
|
|
44
44
|
buffer_size: 8192,
|
|
45
|
+
flow_control_window_bytes: 1024 * 1024,
|
|
45
46
|
order_mode: "Unordered",
|
|
46
47
|
order_timeout_ms: 100,
|
|
47
48
|
micro_batch_us: 100,
|
|
48
49
|
};
|
|
49
50
|
}
|
|
50
|
-
/**
|
|
51
|
+
/** Rust `ClientConfig::low_latency` 的 Node 调优版本,使用更小的 JS 对象队列。 */
|
|
51
52
|
function lowLatencyClientConfig() {
|
|
52
53
|
return {
|
|
53
54
|
enable_metrics: false,
|
|
@@ -60,12 +61,13 @@ function lowLatencyClientConfig() {
|
|
|
60
61
|
keep_alive_interval_ms: 10_000,
|
|
61
62
|
keep_alive_timeout_ms: 2000,
|
|
62
63
|
buffer_size: 16384,
|
|
64
|
+
flow_control_window_bytes: 16 * 1024 * 1024,
|
|
63
65
|
order_mode: "Unordered",
|
|
64
66
|
order_timeout_ms: 50,
|
|
65
67
|
micro_batch_us: 50,
|
|
66
68
|
};
|
|
67
69
|
}
|
|
68
|
-
/**
|
|
70
|
+
/** Rust `ClientConfig::high_throughput` 的 Node 调优版本,使用更小的 JS 对象队列。 */
|
|
69
71
|
function highThroughputClientConfig() {
|
|
70
72
|
return {
|
|
71
73
|
enable_metrics: true,
|
|
@@ -78,6 +80,7 @@ function highThroughputClientConfig() {
|
|
|
78
80
|
keep_alive_interval_ms: 60_000,
|
|
79
81
|
keep_alive_timeout_ms: 10_000,
|
|
80
82
|
buffer_size: 32768,
|
|
83
|
+
flow_control_window_bytes: 16 * 1024 * 1024,
|
|
81
84
|
order_mode: "Unordered",
|
|
82
85
|
order_timeout_ms: 200,
|
|
83
86
|
micro_batch_us: 200,
|
package/dist/index.d.ts
CHANGED
|
@@ -41,7 +41,7 @@ export { parseInstructionUnified, parsePumpfunInstruction, parsePumpswapInstruct
|
|
|
41
41
|
/** Rust `instr` 根模块蛇形命名别名 */
|
|
42
42
|
export { parse_instruction_unified, parse_pumpfun_instruction, parse_pumpswap_instruction, parse_meteora_damm_instruction, parse_meteora_dlmm_instruction, parse_meteora_pools_instruction, parse_pump_fees_instruction, } from "./instr/rust_aliases.js";
|
|
43
43
|
export * as programIds from "./instr/program_ids.js";
|
|
44
|
-
export { YellowstoneGrpc, type SubscribeCallbacks, type DexEventSubscription } from "./grpc/client.js";
|
|
44
|
+
export { YellowstoneGrpc, type SubscribeCallbacks, type DexEventSubscription, type SubscribeDexEventsOptions, type EventQueueOverflowStrategy, } from "./grpc/client.js";
|
|
45
45
|
export { connectYellowstoneGeyser, defaultGeyserConnectConfig, geyserGrpcChannelOptions, type GeyserConnectConfig, } from "./grpc/geyser_connect.js";
|
|
46
46
|
/** 与 Rust `sol_parser_sdk::grpc::event_parser` 模块对应 */
|
|
47
47
|
export * as event_parser from "./grpc/event_parser.js";
|
package/dist/instr/inner.js
CHANGED
|
@@ -48,7 +48,7 @@ function filterDexEvent(ev, filter) {
|
|
|
48
48
|
? (0, types_js_1.eventTypeFilterNormalizeDexEvent)(filter, ev)
|
|
49
49
|
: null;
|
|
50
50
|
}
|
|
51
|
-
function
|
|
51
|
+
function eventCpiDiscriminator(disc) {
|
|
52
52
|
if (bytesEq(disc, 0, EVENT_CPI_PREFIX))
|
|
53
53
|
return (0, binary_js_1.readU64LE)(disc, 8);
|
|
54
54
|
if (bytesEq(disc, 8, EVENT_CPI_SUFFIX))
|
|
@@ -116,14 +116,16 @@ const LOG = {
|
|
|
116
116
|
METEORA_DAMM_INITIALIZE_POOL: [228, 50, 246, 85, 203, 66, 134, 37],
|
|
117
117
|
METEORA_DAMM_CREATE_POSITION: [156, 15, 119, 198, 29, 181, 221, 55],
|
|
118
118
|
METEORA_DAMM_CLOSE_POSITION: [20, 145, 144, 68, 143, 142, 214, 178],
|
|
119
|
-
METEORA_DLMM_SWAP: [
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
119
|
+
METEORA_DLMM_SWAP: [81, 108, 227, 190, 205, 208, 10, 196],
|
|
120
|
+
METEORA_DLMM_SWAP2: [46, 116, 82, 215, 148, 27, 84, 77],
|
|
121
|
+
METEORA_DLMM_ADD_LIQUIDITY: [31, 94, 125, 90, 227, 52, 61, 186],
|
|
122
|
+
METEORA_DLMM_REMOVE_LIQUIDITY: [116, 244, 97, 232, 103, 31, 152, 58],
|
|
123
|
+
METEORA_DLMM_INITIALIZE_POOL: [185, 74, 252, 125, 27, 215, 188, 111],
|
|
123
124
|
METEORA_DLMM_INITIALIZE_BIN_ARRAY: [11, 18, 155, 194, 33, 115, 238, 119],
|
|
124
|
-
METEORA_DLMM_CREATE_POSITION: [
|
|
125
|
-
METEORA_DLMM_CLOSE_POSITION: [
|
|
126
|
-
METEORA_DLMM_CLAIM_FEE: [
|
|
125
|
+
METEORA_DLMM_CREATE_POSITION: [144, 142, 252, 84, 157, 53, 37, 121],
|
|
126
|
+
METEORA_DLMM_CLOSE_POSITION: [255, 196, 16, 107, 28, 202, 53, 128],
|
|
127
|
+
METEORA_DLMM_CLAIM_FEE: [75, 122, 154, 48, 140, 74, 123, 163],
|
|
128
|
+
METEORA_DLMM_CLAIM_FEE2: [232, 171, 242, 97, 58, 77, 35, 45],
|
|
127
129
|
RAYDIUM_LAUNCHLAB_POOL_CREATE: [151, 215, 226, 9, 118, 161, 115, 174],
|
|
128
130
|
RAYDIUM_LAUNCHLAB_TRADE: [189, 219, 127, 211, 78, 230, 97, 238],
|
|
129
131
|
};
|
|
@@ -200,6 +202,28 @@ const IX = {
|
|
|
200
202
|
[80, 85, 209, 72, 24, 206, 177, 108],
|
|
201
203
|
[95, 180, 10, 172, 84, 174, 232, 40],
|
|
202
204
|
],
|
|
205
|
+
METEORA_DLMM: [
|
|
206
|
+
[181, 157, 89, 67, 143, 182, 52, 72],
|
|
207
|
+
[228, 162, 78, 28, 70, 219, 116, 115],
|
|
208
|
+
[169, 32, 79, 137, 136, 232, 70, 137],
|
|
209
|
+
[112, 191, 101, 171, 28, 144, 127, 187],
|
|
210
|
+
[123, 134, 81, 0, 49, 68, 98, 98],
|
|
211
|
+
[174, 90, 35, 115, 186, 40, 147, 226],
|
|
212
|
+
[35, 86, 19, 185, 78, 212, 75, 211],
|
|
213
|
+
[45, 154, 237, 210, 221, 15, 166, 92],
|
|
214
|
+
[73, 59, 36, 120, 237, 83, 108, 198],
|
|
215
|
+
[219, 192, 234, 71, 190, 191, 102, 80],
|
|
216
|
+
[143, 19, 242, 145, 213, 15, 104, 115],
|
|
217
|
+
[46, 82, 125, 146, 85, 141, 228, 153],
|
|
218
|
+
[80, 85, 209, 72, 24, 206, 177, 108],
|
|
219
|
+
[230, 215, 82, 127, 241, 101, 227, 146],
|
|
220
|
+
[248, 198, 158, 145, 225, 117, 135, 200],
|
|
221
|
+
[65, 75, 63, 76, 235, 91, 91, 136],
|
|
222
|
+
[250, 73, 101, 33, 38, 207, 75, 184],
|
|
223
|
+
[43, 215, 247, 132, 137, 60, 243, 81],
|
|
224
|
+
[56, 173, 230, 208, 173, 228, 156, 205],
|
|
225
|
+
[74, 98, 192, 214, 177, 51, 75, 51],
|
|
226
|
+
],
|
|
203
227
|
};
|
|
204
228
|
function firstByteIn(data, allowed) {
|
|
205
229
|
return data.length > 0 && allowed.includes(data[0]);
|
|
@@ -213,7 +237,7 @@ function normalInstructionDataMayParse(programId, data) {
|
|
|
213
237
|
if (programId === program_ids_js_1.RAYDIUM_AMM_V4_PROGRAM_ID)
|
|
214
238
|
return firstByteIn(data, [1, 3, 4, 7, 9, 11]);
|
|
215
239
|
if (programId === program_ids_js_1.METEORA_DLMM_PROGRAM_ID)
|
|
216
|
-
return
|
|
240
|
+
return headIn(data, IX.METEORA_DLMM);
|
|
217
241
|
if (programId === program_ids_js_1.METEORA_DAMM_V2_PROGRAM_ID) {
|
|
218
242
|
return discEq(data, LOG.METEORA_DAMM_INITIALIZE_POOL);
|
|
219
243
|
}
|
|
@@ -243,7 +267,7 @@ function parseInnerCompiledInstructionIfSupported(data, accounts, signature, slo
|
|
|
243
267
|
return (0, mod_js_1.parseInstructionUnified)(data, accounts, signature, slot, txIndex, blockTimeUs, grpcRecvUs, filter, programId);
|
|
244
268
|
}
|
|
245
269
|
function parsePumpFeesInner(disc, data, metadata) {
|
|
246
|
-
const eventDisc =
|
|
270
|
+
const eventDisc = eventCpiDiscriminator(disc);
|
|
247
271
|
if (eventDisc === null)
|
|
248
272
|
return null;
|
|
249
273
|
if (eventDisc === disc8(LOG.PUMP_FEES_CREATE_FEE_SHARING_CONFIG)) {
|
|
@@ -431,12 +455,10 @@ function parseInnerInstructionUnified(instructionData, accounts, signature, slot
|
|
|
431
455
|
else if (programId === program_ids_js_1.METEORA_DLMM_PROGRAM_ID) {
|
|
432
456
|
if (filter && !(0, types_js_1.eventTypeFilterIncludesMeteoraDlmm)(filter))
|
|
433
457
|
return null;
|
|
434
|
-
|
|
458
|
+
const eventDisc = eventCpiDiscriminator(disc);
|
|
459
|
+
if (eventDisc === null)
|
|
435
460
|
return null;
|
|
436
|
-
|
|
437
|
-
decoded.set(disc.subarray(0, 8), 0);
|
|
438
|
-
decoded.set(data, 8);
|
|
439
|
-
ev = (0, meteora_dlmm_js_1.parseDlmmFromDecoded)(decoded, metadata);
|
|
461
|
+
ev = (0, meteora_dlmm_js_1.parseDlmmEventFromData)(eventDisc, data, metadata);
|
|
440
462
|
}
|
|
441
463
|
else if (programId === program_ids_js_1.RAYDIUM_LAUNCHLAB_PROGRAM_ID) {
|
|
442
464
|
if (filter && !(0, types_js_1.eventTypeFilterIncludesRaydiumLaunchlab)(filter))
|