sol-parser-sdk-nodejs 0.4.0 → 0.5.5
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 +22 -4
- package/README_CN.md +22 -4
- package/dist/accounts/mod.d.ts +1 -0
- package/dist/accounts/mod.js +53 -6
- package/dist/accounts/pumpfun.d.ts +16 -0
- package/dist/accounts/pumpfun.js +538 -0
- package/dist/accounts/rust_aliases.d.ts +1 -0
- package/dist/accounts/rust_aliases.js +3 -1
- package/dist/core/account_dispatcher_rpc.js +5 -26
- package/dist/core/account_fill_meteora.d.ts +1 -2
- package/dist/core/account_fill_meteora.js +0 -2
- package/dist/core/account_fill_pumpfun.js +92 -13
- package/dist/core/account_fill_pumpswap.js +50 -0
- package/dist/core/account_fill_raydium_launchlab.d.ts +4 -0
- package/dist/core/account_fill_raydium_launchlab.js +20 -0
- package/dist/core/dex_event.d.ts +283 -17
- package/dist/core/pumpfun_fee_enrich.d.ts +5 -0
- package/dist/core/pumpfun_fee_enrich.js +131 -0
- package/dist/core/unified_parser.js +2 -0
- package/dist/grpc/client.d.ts +26 -1
- package/dist/grpc/client.js +279 -0
- package/dist/grpc/log_instr_dedup.d.ts +2 -0
- package/dist/grpc/log_instr_dedup.js +378 -0
- package/dist/grpc/order_buffer.d.ts +27 -0
- package/dist/grpc/order_buffer.js +166 -0
- package/dist/grpc/program_ids.d.ts +5 -3
- package/dist/grpc/program_ids.js +12 -5
- package/dist/grpc/types.d.ts +17 -6
- package/dist/grpc/types.js +265 -153
- package/dist/grpc/yellowstone_parse.d.ts +3 -1
- package/dist/grpc/yellowstone_parse.js +13 -10
- package/dist/index.d.ts +9 -7
- package/dist/index.js +33 -7
- package/dist/instr/meteora_damm_ix.js +4 -1
- package/dist/instr/meteora_dlmm_ix.d.ts +2 -0
- package/dist/instr/meteora_dlmm_ix.js +134 -0
- package/dist/instr/meteora_pools_ix.d.ts +2 -0
- package/dist/instr/meteora_pools_ix.js +78 -0
- package/dist/instr/mod.d.ts +4 -1
- package/dist/instr/mod.js +45 -18
- package/dist/instr/program_ids.d.ts +1 -5
- package/dist/instr/program_ids.js +4 -6
- package/dist/instr/pump_fees_ix.d.ts +2 -0
- package/dist/instr/pump_fees_ix.js +166 -0
- package/dist/instr/pumpfun_ix.js +272 -1
- package/dist/instr/pumpswap_ix.js +36 -2
- package/dist/instr/raydium_clmm_ix.js +73 -52
- package/dist/instr/raydium_launchlab_ix.d.ts +8 -0
- package/dist/instr/raydium_launchlab_ix.js +125 -0
- package/dist/instr/rust_aliases.d.ts +3 -0
- package/dist/instr/rust_aliases.js +7 -1
- package/dist/logs/discriminator_lut.d.ts +1 -1
- package/dist/logs/discriminator_lut.js +2 -0
- package/dist/logs/optimized_matcher.js +130 -25
- package/dist/logs/program_log_discriminators.d.ts +10 -0
- package/dist/logs/program_log_discriminators.js +10 -0
- package/dist/logs/pump.d.ts +2 -0
- package/dist/logs/pump.js +122 -2
- package/dist/logs/pump_amm.js +1 -1
- package/dist/logs/pump_fees.d.ts +23 -0
- package/dist/logs/pump_fees.js +364 -0
- package/dist/logs/raydium_launchlab.d.ts +10 -0
- package/dist/logs/raydium_launchlab.js +84 -0
- package/dist/rpc_transaction.d.ts +2 -0
- package/dist/rpc_transaction.js +14 -6
- package/dist/shredstream/client.d.ts +4 -1
- package/dist/shredstream/client.js +18 -14
- package/dist/shredstream/index.d.ts +1 -1
- package/dist/shredstream/index.js +1 -1
- package/dist/shredstream/instruction_parse.d.ts +3 -3
- package/dist/shredstream/instruction_parse.js +38 -13
- package/dist/util/market.d.ts +18 -0
- package/dist/util/market.js +54 -0
- package/package.json +1 -1
package/dist/rpc_transaction.js
CHANGED
|
@@ -13,7 +13,9 @@ const bs58_1 = __importDefault(require("bs58"));
|
|
|
13
13
|
const web3_js_1 = require("@solana/web3.js");
|
|
14
14
|
const account_dispatcher_rpc_js_1 = require("./core/account_dispatcher_rpc.js");
|
|
15
15
|
const common_filler_rpc_js_1 = require("./core/common_filler_rpc.js");
|
|
16
|
+
const pumpfun_fee_enrich_js_1 = require("./core/pumpfun_fee_enrich.js");
|
|
16
17
|
const rpc_invoke_map_js_1 = require("./core/rpc_invoke_map.js");
|
|
18
|
+
const log_instr_dedup_js_1 = require("./grpc/log_instr_dedup.js");
|
|
17
19
|
const mod_js_1 = require("./instr/mod.js");
|
|
18
20
|
const optimized_matcher_js_1 = require("./logs/optimized_matcher.js");
|
|
19
21
|
const DEFAULT_PK = web3_js_1.PublicKey.default.toBase58();
|
|
@@ -71,6 +73,7 @@ function applyRpcFills(events, msg, meta) {
|
|
|
71
73
|
*/
|
|
72
74
|
function applyAccountFillsToLogEvents(events, msg, meta) {
|
|
73
75
|
applyRpcFills(events, msg, meta);
|
|
76
|
+
(0, pumpfun_fee_enrich_js_1.enrichPumpfunSameTxPostMerge)(events);
|
|
74
77
|
}
|
|
75
78
|
/**
|
|
76
79
|
* 解析已获取的 `VersionedTransactionResponse`(顺序:指令 → 日志 → 账户/数据填充)。
|
|
@@ -88,21 +91,26 @@ function parseRpcTransaction(tx, signature, filter, options) {
|
|
|
88
91
|
}
|
|
89
92
|
const meta = tx.meta ?? null;
|
|
90
93
|
const slot = tx.slot;
|
|
91
|
-
const blockTimeUs = tx.blockTime != null ? tx.blockTime * 1_000_000 : undefined;
|
|
94
|
+
const blockTimeUs = options?.blockTimeUs ?? (tx.blockTime != null ? tx.blockTime * 1_000_000 : undefined);
|
|
92
95
|
const grpcRecvUs = options?.grpcRecvUs ?? Math.floor(Date.now() * 1000);
|
|
96
|
+
const txIndex = options?.txIndex ?? 0;
|
|
93
97
|
const rb = recentBlockhashBytes(msg.recentBlockhash);
|
|
94
|
-
const
|
|
95
|
-
parseOuterAndInnerInstructions(msg, meta, signature, slot,
|
|
98
|
+
const instructionEvents = [];
|
|
99
|
+
parseOuterAndInnerInstructions(msg, meta, signature, slot, txIndex, blockTimeUs, grpcRecvUs, filter, instructionEvents);
|
|
100
|
+
const logEvents = [];
|
|
96
101
|
let isCreatedBuy = false;
|
|
97
102
|
for (const log of meta?.logMessages ?? []) {
|
|
98
|
-
const e = (0, optimized_matcher_js_1.parseLogOptimized)(log, signature, slot,
|
|
103
|
+
const e = (0, optimized_matcher_js_1.parseLogOptimized)(log, signature, slot, txIndex, blockTimeUs, grpcRecvUs, filter, isCreatedBuy, rb);
|
|
99
104
|
if (e) {
|
|
100
105
|
if ("PumpFunCreate" in e || "PumpFunCreateV2" in e)
|
|
101
106
|
isCreatedBuy = true;
|
|
102
|
-
|
|
107
|
+
logEvents.push(e);
|
|
103
108
|
}
|
|
104
109
|
}
|
|
105
|
-
applyRpcFills(
|
|
110
|
+
applyRpcFills(instructionEvents, msg, meta);
|
|
111
|
+
applyRpcFills(logEvents, msg, meta);
|
|
112
|
+
const events = (0, log_instr_dedup_js_1.dedupeLogInstructionEvents)(logEvents, instructionEvents);
|
|
113
|
+
(0, pumpfun_fee_enrich_js_1.enrichPumpfunSameTxPostMerge)(events);
|
|
106
114
|
return { ok: true, events };
|
|
107
115
|
}
|
|
108
116
|
var account_dispatcher_rpc_js_2 = require("./core/account_dispatcher_rpc.js");
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type DexEvent } from "../core/dex_event.js";
|
|
2
|
+
import type { EventTypeFilter } from "../grpc/types.js";
|
|
2
3
|
import { type ShredStreamConfig } from "./config.js";
|
|
3
4
|
/** 订阅周期内累计(用于排查「无 gRPC 包 / 解码失败 / 无 DEX 事件」) */
|
|
4
5
|
export type ShredStreamReceiveStats = {
|
|
@@ -48,7 +49,9 @@ export declare class ShredStreamClient {
|
|
|
48
49
|
* 订阅 DEX 事件(自动重连);返回队列供轮询消费(与 Rust `subscribe` 一致)。
|
|
49
50
|
* 重连循环使用订阅时刻的配置快照(与 Rust 在 `tokio::spawn` 前 `config.clone()` 一致)。
|
|
50
51
|
*/
|
|
51
|
-
subscribe(): Promise<ShredEventQueue>;
|
|
52
|
+
subscribe(eventTypeFilter?: EventTypeFilter): Promise<ShredEventQueue>;
|
|
53
|
+
/** 与 Rust `subscribe_with_filter` 对齐:在解析热路径按事件类型预过滤。 */
|
|
54
|
+
subscribeWithFilter(eventTypeFilter?: EventTypeFilter): Promise<ShredEventQueue>;
|
|
52
55
|
/** 停止订阅并中止当前流 */
|
|
53
56
|
stop(): Promise<void>;
|
|
54
57
|
private runReconnectLoop;
|
|
@@ -193,7 +193,7 @@ class ShredStreamClient {
|
|
|
193
193
|
* 订阅 DEX 事件(自动重连);返回队列供轮询消费(与 Rust `subscribe` 一致)。
|
|
194
194
|
* 重连循环使用订阅时刻的配置快照(与 Rust 在 `tokio::spawn` 前 `config.clone()` 一致)。
|
|
195
195
|
*/
|
|
196
|
-
async subscribe() {
|
|
196
|
+
async subscribe(eventTypeFilter) {
|
|
197
197
|
await this.stop();
|
|
198
198
|
this.receiveStats = {
|
|
199
199
|
entryMessagesReceived: 0,
|
|
@@ -205,9 +205,13 @@ class ShredStreamClient {
|
|
|
205
205
|
const ac = new AbortController();
|
|
206
206
|
this.loopAbort = ac;
|
|
207
207
|
const configSnapshot = { ...this.config };
|
|
208
|
-
this.loopPromise = this.runReconnectLoop(queue, ac.signal, configSnapshot);
|
|
208
|
+
this.loopPromise = this.runReconnectLoop(queue, ac.signal, configSnapshot, eventTypeFilter);
|
|
209
209
|
return queue;
|
|
210
210
|
}
|
|
211
|
+
/** 与 Rust `subscribe_with_filter` 对齐:在解析热路径按事件类型预过滤。 */
|
|
212
|
+
async subscribeWithFilter(eventTypeFilter) {
|
|
213
|
+
return this.subscribe(eventTypeFilter);
|
|
214
|
+
}
|
|
211
215
|
/** 停止订阅并中止当前流 */
|
|
212
216
|
async stop() {
|
|
213
217
|
this.loopAbort?.abort();
|
|
@@ -219,7 +223,7 @@ class ShredStreamClient {
|
|
|
219
223
|
this.loopPromise = null;
|
|
220
224
|
}
|
|
221
225
|
}
|
|
222
|
-
async runReconnectLoop(queue, signal, config) {
|
|
226
|
+
async runReconnectLoop(queue, signal, config, eventTypeFilter) {
|
|
223
227
|
let delay = config.reconnect_delay_ms;
|
|
224
228
|
let attempts = 0;
|
|
225
229
|
while (!signal.aborted) {
|
|
@@ -230,7 +234,7 @@ class ShredStreamClient {
|
|
|
230
234
|
}
|
|
231
235
|
attempts += 1;
|
|
232
236
|
try {
|
|
233
|
-
await this.streamOnce(queue, signal, config);
|
|
237
|
+
await this.streamOnce(queue, signal, config, eventTypeFilter);
|
|
234
238
|
delay = config.reconnect_delay_ms;
|
|
235
239
|
attempts = 0;
|
|
236
240
|
}
|
|
@@ -247,7 +251,7 @@ class ShredStreamClient {
|
|
|
247
251
|
}
|
|
248
252
|
}
|
|
249
253
|
/** 与 Rust `stream_events` + `connect_with_config`(tonic Endpoint / Grpc 消息上限)一致 */
|
|
250
|
-
streamOnce(queue, signal, config) {
|
|
254
|
+
streamOnce(queue, signal, config, eventTypeFilter) {
|
|
251
255
|
if (signal.aborted)
|
|
252
256
|
return Promise.resolve();
|
|
253
257
|
const target = grpcTarget(this.endpoint);
|
|
@@ -272,7 +276,7 @@ class ShredStreamClient {
|
|
|
272
276
|
if (signal.aborted)
|
|
273
277
|
return;
|
|
274
278
|
try {
|
|
275
|
-
void this.processEntryMessage(entry, queue);
|
|
279
|
+
void this.processEntryMessage(entry, queue, eventTypeFilter);
|
|
276
280
|
}
|
|
277
281
|
catch (err) {
|
|
278
282
|
console.error("processEntryMessage:", err);
|
|
@@ -293,7 +297,7 @@ class ShredStreamClient {
|
|
|
293
297
|
});
|
|
294
298
|
});
|
|
295
299
|
}
|
|
296
|
-
async processEntryMessage(entry, queue) {
|
|
300
|
+
async processEntryMessage(entry, queue, eventTypeFilter) {
|
|
297
301
|
this.receiveStats.entryMessagesReceived += 1;
|
|
298
302
|
const recvUs = (0, unified_parser_js_1.nowUs)();
|
|
299
303
|
const slotNum = toSlotNumber(entry.slot);
|
|
@@ -312,18 +316,18 @@ class ShredStreamClient {
|
|
|
312
316
|
const conn = this.config.connection;
|
|
313
317
|
if (conn) {
|
|
314
318
|
try {
|
|
315
|
-
await this.processEntryMessageWithAlt(decoded, slotNum, recvUs, queue, bytes.length, conn);
|
|
319
|
+
await this.processEntryMessageWithAlt(decoded, slotNum, recvUs, queue, bytes.length, conn, eventTypeFilter);
|
|
316
320
|
}
|
|
317
321
|
catch (e) {
|
|
318
322
|
console.warn(`[shredstream] ALT/RPC 解析失败 slot=${slotNum}:`, e);
|
|
319
|
-
this.processEntryMessageSync(decoded, slotNum, recvUs, queue, bytes.length);
|
|
323
|
+
this.processEntryMessageSync(decoded, slotNum, recvUs, queue, bytes.length, eventTypeFilter);
|
|
320
324
|
}
|
|
321
325
|
return;
|
|
322
326
|
}
|
|
323
|
-
this.processEntryMessageSync(decoded, slotNum, recvUs, queue, bytes.length);
|
|
327
|
+
this.processEntryMessageSync(decoded, slotNum, recvUs, queue, bytes.length, eventTypeFilter);
|
|
324
328
|
}
|
|
325
329
|
/** 无 RPC:仅用静态账户表 */
|
|
326
|
-
processEntryMessageSync(decoded, slotNum, recvUs, queue, entriesBytesLen) {
|
|
330
|
+
processEntryMessageSync(decoded, slotNum, recvUs, queue, entriesBytesLen, eventTypeFilter) {
|
|
327
331
|
let txTotal = 0;
|
|
328
332
|
let evTotal = 0;
|
|
329
333
|
/** 与 golang `shredstream_entries` 一致:单条 gRPC 消息内跨所有 Solana Entry 的连续下标 */
|
|
@@ -336,7 +340,7 @@ class ShredStreamClient {
|
|
|
336
340
|
const txIndex = globalTxIndex++;
|
|
337
341
|
if (!tx?.signature)
|
|
338
342
|
continue;
|
|
339
|
-
const events = (0, instruction_parse_js_1.dexEventsFromShredWasmTx)(tx, slotNum, txIndex, recvUs,
|
|
343
|
+
const events = (0, instruction_parse_js_1.dexEventsFromShredWasmTx)(tx, slotNum, txIndex, recvUs, eventTypeFilter);
|
|
340
344
|
evTotal += events.length;
|
|
341
345
|
for (const ev of events) {
|
|
342
346
|
setGrpcRecvUsMut(ev, recvUs);
|
|
@@ -351,7 +355,7 @@ class ShredStreamClient {
|
|
|
351
355
|
}
|
|
352
356
|
}
|
|
353
357
|
/** 拉取 ALT 后完整账户表解析 */
|
|
354
|
-
async processEntryMessageWithAlt(decoded, slotNum, recvUs, queue, entriesBytesLen, conn) {
|
|
358
|
+
async processEntryMessageWithAlt(decoded, slotNum, recvUs, queue, entriesBytesLen, conn, eventTypeFilter) {
|
|
355
359
|
const altKeys = new Set();
|
|
356
360
|
for (const outer of decoded) {
|
|
357
361
|
for (const tx of outer) {
|
|
@@ -373,7 +377,7 @@ class ShredStreamClient {
|
|
|
373
377
|
if (!tx?.signature)
|
|
374
378
|
continue;
|
|
375
379
|
const fullKeys = (0, alt_lookup_js_1.fullAccountKeyStringsFromShredTx)(tx, altMap);
|
|
376
|
-
const events = (0, instruction_parse_js_1.dexEventsFromShredWasmTxWithFullKeys)(tx, fullKeys, slotNum, txIndex, recvUs,
|
|
380
|
+
const events = (0, instruction_parse_js_1.dexEventsFromShredWasmTxWithFullKeys)(tx, fullKeys, slotNum, txIndex, recvUs, eventTypeFilter);
|
|
377
381
|
evTotal += events.length;
|
|
378
382
|
for (const ev of events) {
|
|
379
383
|
setGrpcRecvUsMut(ev, recvUs);
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* - 仅静态账户键;使用 ALT 的交易账户列表不完整
|
|
6
6
|
* - 无 inner instructions,无法 CPI 解析
|
|
7
7
|
* - 无 block_time
|
|
8
|
-
* - 无交易日志(program logs);客户端对每条交易走 **外层 `parseInstructionUnified`**(与 gRPC 指令解析同源),可产出 `DexEvent`(V0+ALT
|
|
8
|
+
* - 无交易日志(program logs);客户端对每条交易走 **外层 `parseInstructionUnified`**(与 gRPC 指令解析同源),可产出 `DexEvent`(V0+ALT 若账户下标超出静态表则用默认 pubkey best-effort)
|
|
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";
|
|
@@ -8,7 +8,7 @@ exports.wireBytesToShredWasmTx = exports.decodeShredstreamEntriesBincode = expor
|
|
|
8
8
|
* - 仅静态账户键;使用 ALT 的交易账户列表不完整
|
|
9
9
|
* - 无 inner instructions,无法 CPI 解析
|
|
10
10
|
* - 无 block_time
|
|
11
|
-
* - 无交易日志(program logs);客户端对每条交易走 **外层 `parseInstructionUnified`**(与 gRPC 指令解析同源),可产出 `DexEvent`(V0+ALT
|
|
11
|
+
* - 无交易日志(program logs);客户端对每条交易走 **外层 `parseInstructionUnified`**(与 gRPC 指令解析同源),可产出 `DexEvent`(V0+ALT 若账户下标超出静态表则用默认 pubkey best-effort)
|
|
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");
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ShredStream:外层编译指令 → `parseInstructionUnified`(与 gRPC 指令解析同源)。
|
|
3
3
|
* `ShredWasmTx` 来自线格式交易经 `@solana/web3.js` 反序列化(见 `wire_to_shred_tx.ts`),非 WASM。
|
|
4
|
-
*
|
|
4
|
+
* 有 `ShredStreamConfig.connection` 时可展开 V0 ALT;无 RPC 时用静态账户表 + 默认 pubkey best-effort。
|
|
5
5
|
*/
|
|
6
6
|
import type { MessageHeader } from "@solana/web3.js";
|
|
7
|
-
import type
|
|
7
|
+
import { type DexEvent } from "../core/dex_event.js";
|
|
8
8
|
import type { EventTypeFilter } from "../grpc/types.js";
|
|
9
9
|
export type ShredWasmCompiledIx = {
|
|
10
10
|
programIdIndex: number;
|
|
@@ -30,5 +30,5 @@ export type ShredWasmTx = {
|
|
|
30
30
|
* 使用已解析的完整账户表(静态+ALT)解析外层指令。
|
|
31
31
|
*/
|
|
32
32
|
export declare function dexEventsFromShredWasmTxWithFullKeys(tx: ShredWasmTx, fullAccountKeys: string[], slot: number, txIndex: number, grpcRecvUs: number, eventTypeFilter?: EventTypeFilter): DexEvent[];
|
|
33
|
-
/** 仅静态账户表(无 RPC 时;V0+ALT
|
|
33
|
+
/** 仅静态账户表(无 RPC 时;V0+ALT 缺失账户以默认 pubkey 占位) */
|
|
34
34
|
export declare function dexEventsFromShredWasmTx(tx: ShredWasmTx, slot: number, txIndex: number, grpcRecvUs: number, eventTypeFilter?: EventTypeFilter): DexEvent[];
|
|
@@ -2,12 +2,37 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.dexEventsFromShredWasmTxWithFullKeys = dexEventsFromShredWasmTxWithFullKeys;
|
|
4
4
|
exports.dexEventsFromShredWasmTx = dexEventsFromShredWasmTx;
|
|
5
|
+
const dex_event_js_1 = require("../core/dex_event.js");
|
|
6
|
+
const pumpfun_fee_enrich_js_1 = require("../core/pumpfun_fee_enrich.js");
|
|
5
7
|
const mod_js_1 = require("../instr/mod.js");
|
|
8
|
+
const program_ids_js_1 = require("../instr/program_ids.js");
|
|
6
9
|
function asU8(b) {
|
|
7
10
|
if (b instanceof Uint8Array)
|
|
8
11
|
return b;
|
|
9
12
|
return Uint8Array.from(b);
|
|
10
13
|
}
|
|
14
|
+
const UNKNOWN_PROGRAM_CANDIDATES = [
|
|
15
|
+
program_ids_js_1.PUMPFUN_PROGRAM_ID,
|
|
16
|
+
program_ids_js_1.PUMPSWAP_PROGRAM_ID,
|
|
17
|
+
program_ids_js_1.PUMP_FEES_PROGRAM_ID,
|
|
18
|
+
program_ids_js_1.RAYDIUM_LAUNCHLAB_PROGRAM_ID,
|
|
19
|
+
program_ids_js_1.RAYDIUM_CPMM_PROGRAM_ID,
|
|
20
|
+
program_ids_js_1.RAYDIUM_CLMM_PROGRAM_ID,
|
|
21
|
+
program_ids_js_1.RAYDIUM_AMM_V4_PROGRAM_ID,
|
|
22
|
+
program_ids_js_1.ORCA_WHIRLPOOL_PROGRAM_ID,
|
|
23
|
+
program_ids_js_1.METEORA_POOLS_PROGRAM_ID,
|
|
24
|
+
program_ids_js_1.METEORA_DAMM_V2_PROGRAM_ID,
|
|
25
|
+
program_ids_js_1.METEORA_DLMM_PROGRAM_ID,
|
|
26
|
+
];
|
|
27
|
+
const SHRED_DEFAULT_PUBKEY = (0, dex_event_js_1.defaultPubkey)();
|
|
28
|
+
function ixAccountStrings(fullAccountKeys, accBytes) {
|
|
29
|
+
const accountStrs = [];
|
|
30
|
+
for (let i = 0; i < accBytes.length; i++) {
|
|
31
|
+
const ai = accBytes[i];
|
|
32
|
+
accountStrs.push(ai < fullAccountKeys.length ? fullAccountKeys[ai] : SHRED_DEFAULT_PUBKEY);
|
|
33
|
+
}
|
|
34
|
+
return accountStrs;
|
|
35
|
+
}
|
|
11
36
|
/**
|
|
12
37
|
* 使用已解析的完整账户表(静态+ALT)解析外层指令。
|
|
13
38
|
*/
|
|
@@ -18,30 +43,30 @@ function dexEventsFromShredWasmTxWithFullKeys(tx, fullAccountKeys, slot, txIndex
|
|
|
18
43
|
const out = [];
|
|
19
44
|
for (const rawIx of ixs) {
|
|
20
45
|
const pidIdx = rawIx.programIdIndex;
|
|
21
|
-
if (!Number.isFinite(pidIdx) || pidIdx < 0
|
|
46
|
+
if (!Number.isFinite(pidIdx) || pidIdx < 0)
|
|
22
47
|
continue;
|
|
23
|
-
const programId = fullAccountKeys[pidIdx];
|
|
24
48
|
const accBytes = asU8(rawIx.accounts);
|
|
25
49
|
const data = asU8(rawIx.data);
|
|
26
|
-
const accountStrs =
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
50
|
+
const accountStrs = ixAccountStrings(fullAccountKeys, accBytes);
|
|
51
|
+
if (pidIdx >= fullAccountKeys.length) {
|
|
52
|
+
for (const programId of UNKNOWN_PROGRAM_CANDIDATES) {
|
|
53
|
+
const ev = (0, mod_js_1.parseInstructionUnified)(data, accountStrs, tx.signature, slot, txIndex, undefined, grpcRecvUs, eventTypeFilter, programId);
|
|
54
|
+
if (ev) {
|
|
55
|
+
out.push(ev);
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
33
58
|
}
|
|
34
|
-
accountStrs.push(fullAccountKeys[ai]);
|
|
35
|
-
}
|
|
36
|
-
if (oob)
|
|
37
59
|
continue;
|
|
60
|
+
}
|
|
61
|
+
const programId = fullAccountKeys[pidIdx];
|
|
38
62
|
const ev = (0, mod_js_1.parseInstructionUnified)(data, accountStrs, tx.signature, slot, txIndex, undefined, grpcRecvUs, eventTypeFilter, programId);
|
|
39
63
|
if (ev)
|
|
40
64
|
out.push(ev);
|
|
41
65
|
}
|
|
66
|
+
(0, pumpfun_fee_enrich_js_1.enrichPumpfunSameTxPostMerge)(out);
|
|
42
67
|
return out;
|
|
43
68
|
}
|
|
44
|
-
/** 仅静态账户表(无 RPC 时;V0+ALT
|
|
69
|
+
/** 仅静态账户表(无 RPC 时;V0+ALT 缺失账户以默认 pubkey 占位) */
|
|
45
70
|
function dexEventsFromShredWasmTx(tx, slot, txIndex, grpcRecvUs, eventTypeFilter) {
|
|
46
71
|
return dexEventsFromShredWasmTxWithFullKeys(tx, tx.accounts, slot, txIndex, grpcRecvUs, eventTypeFilter);
|
|
47
72
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type NumericAmount = bigint | number | string;
|
|
2
|
+
export type NormalizedTradeSide = "Buy" | "Sell";
|
|
3
|
+
/**
|
|
4
|
+
* Convert a Q64.64 sqrt price into quote-token units per one base token.
|
|
5
|
+
*/
|
|
6
|
+
export declare function sqrtPriceX64ToPrice(sqrtPriceX64: NumericAmount, baseDecimals: number, quoteDecimals: number): number;
|
|
7
|
+
/**
|
|
8
|
+
* Compute quote-token price per one base token from raw vault balances.
|
|
9
|
+
*/
|
|
10
|
+
export declare function vaultPriceFromBalances(baseRaw: NumericAmount, quoteRaw: NumericAmount, baseDecimals: number, quoteDecimals: number): number | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Positive watched-token delta means Buy; negative means Sell.
|
|
13
|
+
*/
|
|
14
|
+
export declare function normalizeBuySellFromTokenDelta(tokenDelta: NumericAmount): NormalizedTradeSide | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* If input is quote, the user buys base. If input is base, the user sells base.
|
|
17
|
+
*/
|
|
18
|
+
export declare function normalizeBuySellFromInputMint(inputMint: string, baseMint: string, quoteMint: string): NormalizedTradeSide | undefined;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sqrtPriceX64ToPrice = sqrtPriceX64ToPrice;
|
|
4
|
+
exports.vaultPriceFromBalances = vaultPriceFromBalances;
|
|
5
|
+
exports.normalizeBuySellFromTokenDelta = normalizeBuySellFromTokenDelta;
|
|
6
|
+
exports.normalizeBuySellFromInputMint = normalizeBuySellFromInputMint;
|
|
7
|
+
function amountToNumber(value) {
|
|
8
|
+
if (typeof value === "bigint")
|
|
9
|
+
return Number(value);
|
|
10
|
+
if (typeof value === "number")
|
|
11
|
+
return value;
|
|
12
|
+
if (value.trim() === "")
|
|
13
|
+
throw new Error("amount must not be empty");
|
|
14
|
+
return Number(value);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Convert a Q64.64 sqrt price into quote-token units per one base token.
|
|
18
|
+
*/
|
|
19
|
+
function sqrtPriceX64ToPrice(sqrtPriceX64, baseDecimals, quoteDecimals) {
|
|
20
|
+
const sqrt = amountToNumber(sqrtPriceX64) / 2 ** 64;
|
|
21
|
+
return sqrt * sqrt * 10 ** (baseDecimals - quoteDecimals);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Compute quote-token price per one base token from raw vault balances.
|
|
25
|
+
*/
|
|
26
|
+
function vaultPriceFromBalances(baseRaw, quoteRaw, baseDecimals, quoteDecimals) {
|
|
27
|
+
const base = amountToNumber(baseRaw);
|
|
28
|
+
if (base === 0)
|
|
29
|
+
return undefined;
|
|
30
|
+
return (amountToNumber(quoteRaw) / base) * 10 ** (baseDecimals - quoteDecimals);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Positive watched-token delta means Buy; negative means Sell.
|
|
34
|
+
*/
|
|
35
|
+
function normalizeBuySellFromTokenDelta(tokenDelta) {
|
|
36
|
+
const delta = amountToNumber(tokenDelta);
|
|
37
|
+
if (delta > 0)
|
|
38
|
+
return "Buy";
|
|
39
|
+
if (delta < 0)
|
|
40
|
+
return "Sell";
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* If input is quote, the user buys base. If input is base, the user sells base.
|
|
45
|
+
*/
|
|
46
|
+
function normalizeBuySellFromInputMint(inputMint, baseMint, quoteMint) {
|
|
47
|
+
if (baseMint === quoteMint)
|
|
48
|
+
return undefined;
|
|
49
|
+
if (inputMint === quoteMint)
|
|
50
|
+
return "Buy";
|
|
51
|
+
if (inputMint === baseMint)
|
|
52
|
+
return "Sell";
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
package/package.json
CHANGED